From 5af0f070284de2dd5aa59158f5f5ebd760d899ec Mon Sep 17 00:00:00 2001 From: "smh22@boulderdash.cl.cam.ac.uk" Date: Wed, 12 Feb 2003 18:04:40 +0000 Subject: [PATCH] bitkeeper revision 1.22.4.1 (3e4a8cb8Aw-XeXojqgYl10tZjNiQyA) Initial 'debugging' support (aka keyboard and serial rx int handlers :-) Also current state of Alex's IDE stuff (not yet completely working). You need to config this up to use it. --- .rootkeys | 14 + BitKeeper/etc/ignore | 16 + xen-2.4.16/drivers/block/xen_block.c | 620 +++++++ xen-2.4.16/drivers/char/Makefile | 8 + xen-2.4.16/drivers/char/xen_kbd.c | 113 ++ xen-2.4.16/drivers/char/xen_serial.c | 93 + xen-2.4.16/drivers/ide/ide-disk.c.orig | 1550 +++++++++++++++++ .../arch/xeno/drivers/block/xl_block.c | 827 +++++++++ .../arch/xeno/drivers/block/xl_block_test.c | 233 +++ .../arch/xeno/drivers/dom0/dom0_block.c | 27 + .../drivers/block/Config.in | 51 + xenolinux-2.4.16-sparse/fs/partitions/check.c | 443 +++++ xenolinux-2.4.16-sparse/fs/partitions/msdos.c | 642 +++++++ xenolinux-2.4.16-sparse/include/linux/blk.h | 416 +++++ xenolinux-2.4.16-sparse/include/linux/major.h | 199 +++ xenolinux-2.4.16-sparse/init/main.c | 871 +++++++++ 16 files changed, 6123 insertions(+) create mode 100644 xen-2.4.16/drivers/block/xen_block.c create mode 100644 xen-2.4.16/drivers/char/Makefile create mode 100644 xen-2.4.16/drivers/char/xen_kbd.c create mode 100644 xen-2.4.16/drivers/char/xen_serial.c create mode 100644 xen-2.4.16/drivers/ide/ide-disk.c.orig create mode 100644 xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c create mode 100644 xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c create mode 100644 xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c create mode 100644 xenolinux-2.4.16-sparse/drivers/block/Config.in create mode 100644 xenolinux-2.4.16-sparse/fs/partitions/check.c create mode 100644 xenolinux-2.4.16-sparse/fs/partitions/msdos.c create mode 100644 xenolinux-2.4.16-sparse/include/linux/blk.h create mode 100644 xenolinux-2.4.16-sparse/include/linux/major.h create mode 100644 xenolinux-2.4.16-sparse/init/main.c diff --git a/.rootkeys b/.rootkeys index 2304c74597..0ffb115edb 100644 --- a/.rootkeys +++ b/.rootkeys @@ -57,8 +57,13 @@ 3ddb79beME_0abStePF6fU8XLuQnWw xen-2.4.16/drivers/block/elevator.c 3ddb79beNQVrdGyoI4njXhgAjD6a4A xen-2.4.16/drivers/block/genhd.c 3ddb79beyWwLRP_BiM2t1JKgr_plEw xen-2.4.16/drivers/block/ll_rw_blk.c +3e4a8cb7RhubVgsPwO7cK0pgAN8WCQ xen-2.4.16/drivers/block/xen_block.c +3e4a8cb7alzQCDKS7MlioPoHBKYkdQ xen-2.4.16/drivers/char/Makefile +3e4a8cb7WmiYdC-ASGiCSG_CL8vsqg xen-2.4.16/drivers/char/xen_kbd.c +3e4a8cb7nMChlro4wvOBo76n__iCFA xen-2.4.16/drivers/char/xen_serial.c 3ddb79bdhcqD9ebrslr0O0oHqTiiXg xen-2.4.16/drivers/ide/Makefile 3ddb79bdErDn_WC3G-fWxKNR3viLnA xen-2.4.16/drivers/ide/ide-disk.c +3e4a8cb7DcFFHW_fG_OHbY_6f3lPWw xen-2.4.16/drivers/ide/ide-disk.c.orig 3ddb79bdIPNW36FrlId94jTXaW8HoA xen-2.4.16/drivers/ide/ide-dma.c 3ddb79be5Ysvhn4se_Z-LQY_hI6UPw xen-2.4.16/drivers/ide/ide-features.c 3ddb79bdh1ohsWYRH_KdaXr7cqs12w xen-2.4.16/drivers/ide/ide-geometry.c @@ -267,9 +272,12 @@ 3ddb79b7v_Be34as7_mlzFlw65hOjQ xenolinux-2.4.16-sparse/arch/xeno/defconfig 3ddb79b7KUvtx0knQJoRaBDZQeNidg xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile 3ddb79b6Rc0uAOGFthIFxq1KGWZ_Iw xenolinux-2.4.16-sparse/arch/xeno/drivers/block/block.c +3e4a8cb7JECr--r1ipnrkd7NKdbUqQ xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c +3e4a8cb7SLWsLTXQjv7ng6-3hL4pCA xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c 3ddb79b7LLVJBGynxHSOh9A9l97sug xenolinux-2.4.16-sparse/arch/xeno/drivers/console/Makefile 3ddb79b7UG2QiRAU-Wvc1Y_BLigu1Q xenolinux-2.4.16-sparse/arch/xeno/drivers/console/console.c 3ddb79b75eo4PRXkT6Th9popt_SJhg xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/Makefile +3e4a8cb79dT0F4q5T4GEqMj4CtAquQ xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c 3ddb79b7Xyaoep6U0kLvx6Kx7OauDw xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_core.c 3df9ce13K7qSLBtHV-01QHPW62649Q xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_memory.c 3ddb79b7PulSkF9m3c7K5MkxHRf4hA xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_ops.h @@ -313,10 +321,13 @@ 3ddb79b83Zj7Xn2QVhU4HeMuAC9FjA xenolinux-2.4.16-sparse/arch/xeno/mm/init.c 3df9ce13TRWIv0Mawm15zESP7jcT7A xenolinux-2.4.16-sparse/arch/xeno/mm/mmu_context.c 3ddb79b7aKdTkbr3u6aze8tVwGh_TQ xenolinux-2.4.16-sparse/arch/xeno/vmlinux.lds +3e4a8cb7lpFFwT1Iu9zXWc8Ew4klFA xenolinux-2.4.16-sparse/drivers/block/Config.in 3ddb79bbx682YH6vR2zbVOXwg73ULg xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c 3ddb79bcJfHdwrPsjqgI33_OsGdVCg xenolinux-2.4.16-sparse/drivers/block/rd.c 3ddb79bcpVu-IbnqwQqpRqsEbLpsuw xenolinux-2.4.16-sparse/drivers/char/tty_io.c 3e15d5273gfR2fbcYe05kqBSAvCX_w xenolinux-2.4.16-sparse/fs/exec.c +3e4a8cb7kqfJTMeOpPcYxqxv7N18DA xenolinux-2.4.16-sparse/fs/partitions/check.c +3e4a8cb7p079Xxly4uNcouacMSjJLw xenolinux-2.4.16-sparse/fs/partitions/msdos.c 3ddb79b8VFtfWSCrXKPN2K21zd_vtw xenolinux-2.4.16-sparse/include/asm-xeno/a.out.h 3ddb79b8Zzi13p3OAPV25QgiC3THAQ xenolinux-2.4.16-sparse/include/asm-xeno/apic.h 3ddb79baZDlsdV_m6C5CXnWMl15p1g xenolinux-2.4.16-sparse/include/asm-xeno/apicdef.h @@ -422,7 +433,10 @@ 3ddb79ba2qYtIQAT_-vCFkkZUXu_UQ xenolinux-2.4.16-sparse/include/asm-xeno/user.h 3ddb79bbqhb9X9qWOz5Bv4wOzrkITg xenolinux-2.4.16-sparse/include/asm-xeno/vga.h 3ddb79bbA52x94o6uwDYsbzrH2hjzA xenolinux-2.4.16-sparse/include/asm-xeno/xor.h +3e4a8cb7ON8EclY3NN3YPXyMT941hA xenolinux-2.4.16-sparse/include/linux/blk.h +3e4a8cb7GJrKD0z7EF0VZOhdEa01Mw xenolinux-2.4.16-sparse/include/linux/major.h 3ddb79bb_7YG4U75ZmEic9YXWTW7Vw xenolinux-2.4.16-sparse/include/linux/sunrpc/debug.h +3e4a8cb7j05wwb1uPZgY16s68o7qAw xenolinux-2.4.16-sparse/init/main.c 3ddb79bcxkVPfWlZ1PQKvDrfArzOVw xenolinux-2.4.16-sparse/kernel/panic.c 3ddb79bbP31im-mx2NbfthSeqty1Dg xenolinux-2.4.16-sparse/mk 3e15d52e0_j129JPvo7xfYGndVFpwQ xenolinux-2.4.16-sparse/mm/memory.c diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore index 4fe10ce2d4..e5be6b0ec8 100644 --- a/BitKeeper/etc/ignore +++ b/BitKeeper/etc/ignore @@ -3,3 +3,19 @@ PENDING/* xen-2.4.16/common/kernel.c.old xen-2.4.16/common/kernel.c.ok-ish xen-2.4.16/size.image +xen-2.4.16/drivers/block/ll_rw_blk.c.orig +xen-2.4.16/drivers/ide/ide-disk.c.orig +xen-2.4.16/drivers/ide/ide-probe.c.orig +xen-2.4.16/drivers/ide/ide-taskfile.c.orig +xen-2.4.16/drivers/ide/ide.c.orig +xen-2.4.16/drivers/net/e1000/e1000.o +xen-2.4.16/drivers/net/e1000/e1000_ethtool.o +xen-2.4.16/drivers/net/e1000/e1000_hw.o +xen-2.4.16/drivers/net/e1000/e1000_main.o +xen-2.4.16/drivers/net/e1000/e1000_param.o +xen-2.4.16/include/hypervisor-ifs/block.h.orig +xen-2.4.16/include/xeno/blkdev.h.orig +xen-2.4.16/include/xeno/sched.h.orig +xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile.orig +xenolinux-2.4.16-sparse/arch/xeno/drivers/block/block.c.orig +xenolinux-2.4.16-sparse/scripts/kconfig.tk diff --git a/xen-2.4.16/drivers/block/xen_block.c b/xen-2.4.16/drivers/block/xen_block.c new file mode 100644 index 0000000000..b6d0e8993f --- /dev/null +++ b/xen-2.4.16/drivers/block/xen_block.c @@ -0,0 +1,620 @@ +/* + * xen-block.c + * + * process incoming block io requests from guestos's. + */ + +#include +#include +#include +#include +#include +#include /* mark_hyp_event */ +#include +#include +#include +#include + +#define XEN_BLK_DEBUG 0 +#define XEN_BLK_DEBUG_LEVEL KERN_ALERT + +#define XEN_BLK_REQUEST_LIST_SIZE 256 /* very arbitrary */ + +typedef struct blk_request +{ + struct list_head queue; + struct buffer_head *bh; + blk_ring_entry_t request; + struct task_struct *domain; /* requesting domain */ +} blk_request_t; + +static int pending_work; /* which domains have work for us? */ +blk_request_t blk_request_list[XEN_BLK_REQUEST_LIST_SIZE]; +struct list_head free_queue; /* unused requests */ +struct list_head pending_queue; /* waiting for hardware */ +struct list_head io_done_queue; /* request completed. send to guest os */ +spinlock_t free_queue_lock; +spinlock_t pending_queue_lock; +spinlock_t io_done_queue_lock; + +/* some definitions */ +void dumpx (char *buffer, int count); +void printx (char * string); +long do_block_io_op_domain (struct task_struct* task); +int dispatch_rw_block_io (int index); +int dispatch_probe_block_io (int index); +int dispatch_debug_block_io (int index); + +/* + * end_block_io_op + * + * IO has completed. Need to notify the guest operating system. + * Called from hardware interrupt. + */ + +void end_block_io_op(struct buffer_head * bh) +{ + unsigned long cpu_mask; + /* struct list_head *list;*/ + blk_request_t *blk_request = NULL; + unsigned long flags; /* irq save */ + +#if 0 + printk("{E}"); +#endif + if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL + "XEN end_block_io_op, bh: %lx\n", + (unsigned long)bh); + + { + char temp[100]; + sprintf(temp, "endio bh: 0x%p, blkno: 0x%lx", + bh, bh->b_blocknr); + printx(temp); + } + + spin_lock_irqsave(&pending_queue_lock, flags); + /* + list_for_each (list, &pending_queue) + { + blk_request = list_entry(list, blk_request_t, queue); + if (blk_request->bh == bh) + { + break; + } + } + */ + blk_request = (blk_request_t *)bh->b_xen_request; + if (blk_request == NULL) + { + printk (KERN_ALERT + " block io interrupt received for unknown buffer [0x%lx]\n", + (unsigned long) bh); + spin_unlock_irqrestore(&pending_queue_lock, flags); + return; + } + list_del(&blk_request->queue); + spin_unlock_irqrestore(&pending_queue_lock, flags); + + spin_lock_irqsave(&io_done_queue_lock, flags); + list_add_tail(&blk_request->queue, &io_done_queue); + spin_unlock_irqrestore(&io_done_queue_lock, flags); + + /* enqueue work */ + cpu_mask = mark_hyp_event(blk_request->domain, _HYP_EVENT_BLK_RX); + + return; +} + +/* + * flush_blk_queue + * + * Called by the hypervisor synchronously when there is something to do + * (block transfers have completed) + */ + +void flush_blk_queue(void) +{ + blk_request_t *blk_request; + int position = 0; + blk_ring_t *blk_ring; + unsigned long flags; + int loop; + +#if 0 + printk("{F}"); +#endif + /* + if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL + "XEN flush_blk_queue\n"); + */ + + clear_bit(_HYP_EVENT_BLK_RX, ¤t->hyp_events); + + /* NEED LOCK? */ + spin_lock_irqsave(&io_done_queue_lock, flags); + while (!list_empty(&io_done_queue)) + { + blk_request = list_entry(io_done_queue.next, blk_request_t, queue); + list_del (&blk_request->queue); + spin_unlock_irqrestore(&io_done_queue_lock, flags); + + /* place on ring for guest os */ + blk_ring = blk_request->domain->blk_ring_base; + position = blk_ring->rx_prod; + + if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL + "XEN flush_blk_queue [%d]\n", position); + + memcpy(&blk_ring->rx_ring[position], &blk_request->request, + sizeof(blk_ring_entry_t)); + blk_ring->rx_prod = BLK_RX_RING_INC(blk_ring->rx_prod); + + /* notify appropriate guest os */ + set_bit(_EVENT_BLK_RX, + &blk_request->domain->shared_info->events); + + if (0) + { + int temp; + struct buffer_head *bh = blk_request->bh; + char * vbuffer = bh->b_data; + + printk (KERN_ALERT "XEN return block 0x%lx\n", bh->b_blocknr); + + for (temp = 0; temp < bh->b_size; temp++) + { + if (temp % 16 == 0) printk ("[%04x] ", temp); + else if (temp % 4 == 0) printk (" "); + printk ("%02x", + vbuffer[temp] & 255); + if ((temp + 1) % 16 == 0) printk ("\n"); + } + printk ("\n\n"); + } + + /* free the buffer header allocated in do_block_io_op */ + if (blk_request->bh) + { + kfree(blk_request->bh); /* alloc in do_block_io_op */ + } + + spin_lock_irqsave(&free_queue_lock, flags); + list_add_tail(&blk_request->queue, &free_queue); + spin_unlock_irqrestore(&free_queue_lock, flags); + + spin_lock_irqsave(&io_done_queue_lock, flags); + } + spin_unlock_irqrestore(&io_done_queue_lock, flags); + + /* + * now check if there is any pending work from any domain + * that we were previously unable to process. + * + * NOTE: the current algorithm will check _every_ domain + * and wake up _every_ domain that has pending work. + * In the future, we should stop waking up domains once + * there isn't any space for their requests any more + * ALSO, we need to maintain a counter of the last domain + * that we woke up for fairness... we shouldn't restart + * at domain 0 every time (although we might want to special + * case domain 0); + */ + for (loop = 0; loop < XEN_BLOCK_MAX_DOMAINS; loop++) + { + int domain = pending_work & (1 << loop); + + if (domain) + { + struct task_struct *mytask = current; + + /* + printk (KERN_ALERT + "flush_blk_queue pending_work: %x domain: %d loop: %d\n", + pending_work, domain, loop); + */ + /* IS THERE A BETTER WAY OF FINDING THE TASK STRUCT FOR A + * PARTICULAR DOMAIN? + * + * WHAT IF THE TASK GOES AWAY BEFORE WE HAVE A CHANCE TO + * FINISH PROCESSING ALL OF ITS REQUESTS? + */ + while (mytask->domain != loop) + { + mytask = mytask->next_task; + } + do_block_io_op_domain(mytask); + + pending_work = pending_work & !(1 << loop); + /* + printk (KERN_ALERT + " pending_work: %x domain: %d loop: %d\n", + pending_work, domain, loop); + */ + } + } +} + +/* + * do_block_io_op + * + * Accept a block io request from a guest operating system. + * There is an entry in the hypervisor_call_table (xen/arch/i386/entry.S). + */ + +long do_block_io_op (void) +{ + return do_block_io_op_domain(current); +} + +/* + * do_block_io_op + * + * handle the requests for a particular domain + */ + +long do_block_io_op_domain (struct task_struct* task) +{ + blk_ring_t *blk_ring = task->blk_ring_base; + int loop; + +#if 0 + printk("{%d}", current->domain); +#endif + if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL + "XEN do_block_io_op %d %d\n", + blk_ring->tx_cons, blk_ring->tx_prod); + + for (loop = blk_ring->tx_cons; + loop != blk_ring->tx_prod; + loop = BLK_TX_RING_INC(loop)) + { + int status = 1; + + switch (blk_ring->tx_ring[loop].operation) + { + case XEN_BLOCK_READ : + case XEN_BLOCK_WRITE : + { + status = dispatch_rw_block_io(loop); + break; + } + case XEN_BLOCK_PROBE : + { + status = dispatch_probe_block_io(loop); + break; + } + case XEN_BLOCK_DEBUG : + { + status = dispatch_debug_block_io(loop); + break; + } + default : + { + printk (KERN_ALERT "error: unknown block io operation [%d]\n", + blk_ring->tx_ring[loop].operation); + BUG(); + } + } + + if (status) + { + /* unable to successfully issue / complete command, maybe because + * another resource (e.g. disk request buffers) is unavailable. + * stop removing items from the communications ring and try + * again later + */ + + /* + printk ("do_block_io_op_domain domain:%d, pending_work: %x\n", + task->domain, pending_work); + */ + pending_work = pending_work | (1 << task->domain); + /* + printk ("do_block_io_op_domain domain:%d, pending_work: %x\n", + task->domain, pending_work); + */ + break; + } + } + + blk_ring->tx_cons = loop; + + return 0L; +} + +int dispatch_debug_block_io (int index) +{ + struct task_struct *task; + blk_ring_t *blk_ring = current->blk_ring_base; + char * buffer; + char output[1000]; + + int foobar = (unsigned long)blk_ring->tx_ring[index].block_number; + + printk (KERN_ALERT "dispatch_debug_block_io %d\n", foobar); + + buffer = phys_to_virt(blk_ring->tx_ring[index].buffer); + strcpy (buffer, "DEBUG\n"); + + task = current; + sprintf (buffer, "current %d\n", current->domain); + sprintf (buffer, "%s tx: prod: %d, cons: %d, size: %d\n", buffer, + blk_ring->tx_prod, blk_ring->tx_cons, blk_ring->tx_ring_size); + sprintf (buffer, "%s rx: prod: %d, cons: %d, size: %d\n", buffer, + blk_ring->rx_prod, blk_ring->rx_cons, blk_ring->rx_ring_size); + + task = task->next_task; + while (task != current) + { + blk_ring = task->blk_ring_base; + sprintf (buffer, "%stask %d\n", buffer, task->domain); + if (blk_ring != NULL) + { + sprintf (buffer, "%s tx: prod: %d, cons: %d, size: %d\n", + buffer, blk_ring->tx_prod, blk_ring->tx_cons, + blk_ring->tx_ring_size); + sprintf (buffer, "%s rx: prod: %d, cons: %d, size: %d\n", + buffer, blk_ring->rx_prod, blk_ring->rx_cons, + blk_ring->rx_ring_size); + } + task = task->next_task; + } + dumpx(output, foobar); + sprintf (buffer, "%s%s\n", buffer, output); + + return 0; +} + +int dispatch_probe_block_io (int index) +{ + blk_ring_t *blk_ring = current->blk_ring_base; + xen_disk_info_t *xdi; + + xdi = phys_to_virt(blk_ring->tx_ring[index].buffer); + + ide_probe_devices(xdi); + + return 0; +} + +int dispatch_rw_block_io (int index) +{ + blk_ring_t *blk_ring = current->blk_ring_base; + struct buffer_head *bh; + struct request_queue *rq; + int operation; + blk_request_t *blk_request; + unsigned long flags; + + /* + * check to make sure that the block request seems at least + * a bit legitimate + */ + if ((blk_ring->tx_ring[index].block_size & (0x200 - 1)) != 0) + { + printk(KERN_ALERT + " error: dodgy block size: %d\n", + blk_ring->tx_ring[index].block_size); + BUG(); + } + + if (XEN_BLK_DEBUG) + { + printk(XEN_BLK_DEBUG_LEVEL + " tx_cons: %d tx_prod %d index: %d op: %s, pri: %s\n", + blk_ring->tx_cons, blk_ring->tx_prod, index, + (blk_ring->tx_ring[index].operation == XEN_BLOCK_READ ? "read" : "write"), + (blk_ring->tx_ring[index].priority == XEN_BLOCK_SYNC ? "sync" : "async")); + } + + { + char temp[100]; + sprintf(temp, "issue buf: 0x%p, bh: 0x%p, blkno: 0x%lx", + blk_ring->tx_ring[index].buffer, bh, + (unsigned long)blk_ring->tx_ring[index].block_number); + printx(temp); + } + + /* find an empty request slot */ + spin_lock_irqsave(&free_queue_lock, flags); + if (list_empty(&free_queue)) + { + /* printk (KERN_ALERT "dispatch_rw_block_io EMPTY FREE LIST!! %d\n", index); */ + spin_unlock_irqrestore(&free_queue_lock, flags); + return 1; + } + blk_request = list_entry(free_queue.next, blk_request_t, queue); + list_del(&blk_request->queue); + spin_unlock_irqrestore(&free_queue_lock, flags); + + /* place request on pending list */ + spin_lock_irqsave(&pending_queue_lock, flags); + list_add_tail(&blk_request->queue, &pending_queue); + spin_unlock_irqrestore(&pending_queue_lock, flags); + + /* we'll be doing this frequently, would a cache be appropriate? */ + /* free in flush_blk_queue */ + bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), + GFP_KERNEL); + if (!bh) + { + printk(KERN_ALERT "ERROR: bh is null\n"); + BUG(); + } + + /* set just the important bits of the buffer header */ + memset (bh, 0, sizeof (struct buffer_head)); + + bh->b_blocknr = blk_ring->tx_ring[index].block_number; /* block number */ + bh->b_size = blk_ring->tx_ring[index].block_size; /* block size */ + bh->b_dev = blk_ring->tx_ring[index].device; /* device (B_FREE = free) */ + bh->b_rsector = blk_ring->tx_ring[index].sector_number; /* sector number */ + + bh->b_data = phys_to_virt(blk_ring->tx_ring[index].buffer); + /* ptr to data blk */ + bh->b_count.counter = 1; /* users using this block */ + bh->b_xen_request = (void *)blk_request; /* save block request */ + + + if (blk_ring->tx_ring[index].operation == XEN_BLOCK_WRITE) + { + bh->b_state = ((1 << BH_JBD) | /* buffer state bitmap */ + (1 << BH_Mapped) | + (1 << BH_Req) | + (1 << BH_Dirty) | + (1 << BH_Uptodate)); + operation = WRITE; + } + else + { + bh->b_state = (1 << BH_Mapped); /* buffer state bitmap */ + operation = READ; + } + + /* save meta data about request */ + memcpy(&blk_request->request, /* NEED COPY_FROM_USER? */ + &blk_ring->tx_ring[index], sizeof(blk_ring_entry_t)); + blk_request->bh = bh; + blk_request->domain = current; /* save current domain */ + + /* dispatch single block request */ + ll_rw_block(operation, 1, &bh); /* linux top half */ + rq = blk_get_queue(bh->b_rdev); + generic_unplug_device(rq); /* linux bottom half */ + + return 0; +} + +/* + * initialize_block_io + * + * initialize everything for block io + * called from arch/i386/setup.c::start_of_day + */ + +void initialize_block_io () +{ + int loop; + + INIT_LIST_HEAD(&free_queue); + INIT_LIST_HEAD(&pending_queue); + INIT_LIST_HEAD(&io_done_queue); + + spin_lock_init(&free_queue_lock); + spin_lock_init(&pending_queue_lock); + spin_lock_init(&io_done_queue_lock); + + for (loop = 0; loop < XEN_BLK_REQUEST_LIST_SIZE; loop++) + { + list_add_tail(&blk_request_list[loop].queue, &free_queue); + } + + /* + * if bit i is true then domain i has work for us to do. + */ + pending_work = 0; + + return; +} + + +#ifdef DEBUG + +/* + * debug dump_queue + * arguments: queue head, name of queue + */ +void dump_queue(struct list_head *queue, char *name) +{ + struct list_head *list; + int loop = 0; + + printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each (list, queue) + { + printk (" %s %d : %lx n: %lx, p: %lx\n", name, loop++, + (unsigned long)list, + (unsigned long)list->next, (unsigned long)list->prev); + } +} + +void dump_queue_head(struct list_head *queue, char *name) +{ + struct list_head *list; + int loop = 0; + + printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each (list, queue) + { + printk (" %d : %lx n: %lx, p: %lx\n", loop++, + (unsigned long)list, + (unsigned long)list->next, (unsigned long)list->prev); + if (loop >= 5) return; + } +} + +#endif /* DEBUG */ + + +#define debug_block_size 200000 +#define debug_output_size 10 + +static int countx = 0; +static char * arrayx[debug_block_size]; +static int outputx = 0; + +void +printx (char * string) +{ + char * s; + + s = (char *) kmalloc(strlen(string), GFP_KERNEL); + strcpy (s, string); + arrayx[countx++] = s; + + if (countx >= debug_block_size) + { + countx = 0; + printk (KERN_ALERT "printx wrap\n"); + } + +} + +void +dumpx (char *buffer, int count) +{ + int loop; + int start; + + sprintf (buffer, "debug dump\n"); + + /* + for (loop = outputx; + loop < outputx + debug_output_size && loop < countx; + loop ++) + { + sprintf (buffer, "%s%02d:%s\n", buffer, loop, arrayx[loop]); + } + outputx = loop; + */ + + if (count == 0 || count > countx) + { + start = 0; + } + else + { + start = countx - count; + } + + printk (KERN_ALERT "DUMPX BUFFER\n"); + for (loop = start; loop < countx; loop++) + { + printk (KERN_ALERT "%4d %s\n", loop, arrayx[loop]); + } + printk (KERN_ALERT "DUMPX bye bye\n"); +} + diff --git a/xen-2.4.16/drivers/char/Makefile b/xen-2.4.16/drivers/char/Makefile new file mode 100644 index 0000000000..574b7d2d79 --- /dev/null +++ b/xen-2.4.16/drivers/char/Makefile @@ -0,0 +1,8 @@ + +include $(BASEDIR)/Rules.mk + +default: $(OBJS) + $(LD) -r -o driver.o $(OBJS) + +clean: + rm -f *.o *~ core diff --git a/xen-2.4.16/drivers/char/xen_kbd.c b/xen-2.4.16/drivers/char/xen_kbd.c new file mode 100644 index 0000000000..a1f7cea581 --- /dev/null +++ b/xen-2.4.16/drivers/char/xen_kbd.c @@ -0,0 +1,113 @@ +#include + +#define KEYBOARD_IRQ 1 + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* register status bits */ +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ + +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) + + +static void +dispatch_scancode (unsigned char scancode) +{ + /* + * we could be a bit more clever here, but why? + * just add a jump to your debug routine for the appropriate character. + */ + switch (scancode) + { + case 0x01 : /* esc */ + printk (""); + break; + case 0x9e : /* a */ + printk ("a"); + break; + case 0x9f : /* s */ + printk ("s"); + break; + case 0xae : /* c */ + printk ("c"); + break; + case 0xb0 : /* b */ + printk ("b"); + break; + case 0xbb : /* f1 */ + printk (""); + break; + case 0xbc : /* f2 */ + printk (""); + break; + case 0xbd : /* f3 */ + printk (""); + break; + case 0xbe : /* f4 */ + printk (""); + break; + case 0xbf : /* f5 */ + /* xen_block_dump_state(); */ + break; + default : + /* printk ("%x ", scancode); */ + } + + return; +} + + +/* regs should be struct pt_regs */ + +static void keyboard_interrupt(int irq, void *dev_id, void *regs) +{ + unsigned char status = kbd_read_status(); + unsigned int work = 10000; + + while ((--work > 0) && (status & KBD_STAT_OBF)) + { + unsigned char scancode; + + scancode = kbd_read_input(); + + if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) + { + if (status & KBD_STAT_MOUSE_OBF) + /* mouse event, ignore */; + else + dispatch_scancode (scancode); + } + status = kbd_read_status(); + } + + if (!work) + printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status); + + return; +} + + +extern int request_irq(unsigned int, + void (*handler)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); + + +void initialize_keyboard() +{ + if(!request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL)) + printk("initialize_keyboard: failed to alloc IRQ %d\n", KEYBOARD_IRQ); + + return; +} + diff --git a/xen-2.4.16/drivers/char/xen_serial.c b/xen-2.4.16/drivers/char/xen_serial.c new file mode 100644 index 0000000000..9a290ad9ce --- /dev/null +++ b/xen-2.4.16/drivers/char/xen_serial.c @@ -0,0 +1,93 @@ +#include + +/* Register offsets */ +#define NS16550_RBR 0x00 /* receive buffer */ +#define NS16550_THR 0x00 /* transmit holding */ +#define NS16550_IER 0x01 /* interrupt enable */ +#define NS16550_IIR 0x02 /* interrupt identity */ +#define NS16550_FCR 0x02 /* FIFO control */ +#define NS16550_LCR 0x03 /* line control */ +#define NS16550_MCR 0x04 /* MODEM control */ +#define NS16550_LSR 0x05 /* line status */ +#define NS16550_MSR 0x06 /* MODEM status */ +#define NS16550_SCR 0x07 /* scratch */ +#define NS16550_DDL 0x00 /* divisor latch (ls) ( DLAB=1) */ +#define NS16550_DLM 0x01 /* divisor latch (ms) ( DLAB=1) */ + +/* Interrupt enable register */ +#define NS16550_IER_ERDAI 0x01 /* rx data recv'd */ +#define NS16550_IER_ETHREI 0x02 /* tx reg. empty */ +#define NS16550_IER_ELSI 0x04 /* rx line status */ +#define NS16550_IER_EMSI 0x08 /* MODEM status */ + +/* FIFO control register */ +#define NS16550_FCR_ENABLE 0x01 /* enable FIFO */ +#define NS16550_FCR_CLRX 0x02 /* clear Rx FIFO */ +#define NS16550_FCR_CLTX 0x04 /* clear Tx FIFO */ +#define NS16550_FCR_DMA 0x10 /* enter DMA mode */ +#define NS16550_FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ +#define NS16550_FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ +#define NS16550_FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ +#define NS16550_FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ + +/* MODEM control register */ +#define NS16550_MCR_DTR 0x01 /* Data Terminal Ready */ +#define NS16550_MCR_RTS 0x02 /* Request to Send */ +#define NS16550_MCR_OUT1 0x04 /* OUT1: unused */ +#define NS16550_MCR_OUT2 0x08 /* OUT2: interrupt mask */ +#define NS16550_MCR_LOOP 0x10 /* Loop */ + +#define SERIAL_BASE 0x3f8 /* XXX SMH: horrible hardwired COM1 */ +#define SERAIL_ECHO 0 /* XXX SMH: set to 1 for 'echo' on rx */ + + + +static void serial_rx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + int c; + + /* XXX SMH: should probably check this is an RX interrupt :-) */ + + /* clear the interrupt by reading the character */ + c = inb(SERIAL_BASE + NS16550_RBR ); + + if (c==0x04) { + /* This is 'debug me please' => just dump info and halt machine */ + printk("serial_rx_int: got EOT => halting machine.\n"); + printk("\n"); + } + +#ifdef SERIAL_ECHO + printk("%c", c); +#endif + + return; +} + + +extern int request_irq(unsigned int, + void (*handler)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); + + +void initialize_serial() +{ + int fifo = 1; /* must be a ns16550a at least, surely? */ + + if(fifo) { + /* Clear FIFOs, enable, trigger at 1 byte */ + outb(NS16550_FCR_TRG1 | NS16550_FCR_ENABLE | + NS16550_FCR_CLRX | NS16550_FCR_CLTX, SERIAL_BASE+NS16550_FCR); + } + + outb(NS16550_MCR_OUT2, SERIAL_BASE + NS16550_MCR); /* Modem control */ + outb(NS16550_IER_ERDAI, SERIAL_BASE + NS16550_IER ); /* Setup interrupts */ + + /* XXX SMH: this is a hack; probably is IRQ4 but grab both anyway */ + if(!request_irq(4, serial_rx_int, 0, "serial", 0x1234)) + printk("initialize_serial: failed to get IRQ4 :-(\n"); + if(!request_irq(3, serial_rx_int, 0, "serial", 0x5678)) + printk("initialize_serial: failed to get IRQ3 :-(\n"); + + return; +} diff --git a/xen-2.4.16/drivers/ide/ide-disk.c.orig b/xen-2.4.16/drivers/ide/ide-disk.c.orig new file mode 100644 index 0000000000..984e53cd67 --- /dev/null +++ b/xen-2.4.16/drivers/ide/ide-disk.c.orig @@ -0,0 +1,1550 @@ +/* + * linux/drivers/ide/ide-disk.c Version 1.10 June 9, 2000 + * + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + */ + +/* + * Mostly written by Mark Lord + * and Gadi Oxman + * and Andre Hedrick + * + * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. + * + * Version 1.00 move disk only code from ide.c to ide-disk.c + * support optional byte-swapping of all data + * Version 1.01 fix previous byte-swapping code + * Version 1.02 remove ", LBA" from drive identification msgs + * Version 1.03 fix display of id->buf_size for big-endian + * Version 1.04 add /proc configurable settings and S.M.A.R.T support + * Version 1.05 add capacity support for ATA3 >= 8GB + * Version 1.06 get boot-up messages to show full cyl count + * Version 1.07 disable door-locking if it fails + * Version 1.08 fixed CHS/LBA translations for ATA4 > 8GB, + * process of adding new ATA4 compliance. + * fixed problems in allowing fdisk to see + * the entire disk. + * Version 1.09 added increment of rq->sector in ide_multwrite + * added UDMA 3/4 reporting + * Version 1.10 request queue changes, Ultra DMA 100 + * Version 1.11 added 48-bit lba + * Version 1.12 adding taskfile io access method + */ + +#define IDEDISK_VERSION "1.12" + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_BLK_DEV_PDC4030 +#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030) +#else +#define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */ +#endif + +#ifdef CONFIG_IDE_TASKFILE_IO +# undef __TASKFILE__IO /* define __TASKFILE__IO */ +#else /* CONFIG_IDE_TASKFILE_IO */ +# undef __TASKFILE__IO +#endif /* CONFIG_IDE_TASKFILE_IO */ + +#ifndef __TASKFILE__IO + +static void idedisk_bswap_data (void *buffer, int wcount) +{ + u16 *p = buffer; + + while (wcount--) { + *p = *p << 8 | *p >> 8; p++; + *p = *p << 8 | *p >> 8; p++; + } +} + +static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + ide_input_data(drive, buffer, wcount); + if (drive->bswap) + idedisk_bswap_data(buffer, wcount); +} + +static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + if (drive->bswap) { + idedisk_bswap_data(buffer, wcount); + ide_output_data(drive, buffer, wcount); + idedisk_bswap_data(buffer, wcount); + } else + ide_output_data(drive, buffer, wcount); +} + +#endif /* __TASKFILE__IO */ + +/* + * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" + * value for this drive (from its reported identification information). + * + * Returns: 1 if lba_capacity looks sensible + * 0 otherwise + * + * It is called only once for each drive. + */ +static int lba_capacity_is_ok (struct hd_driveid *id) +{ + unsigned long lba_sects, chs_sects, head, tail; + + if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { + printk("48-bit Drive: %llu \n", id->lba_capacity_2); + return 1; + } + + /* + * The ATA spec tells large drives to return + * C/H/S = 16383/16/63 independent of their size. + * Some drives can be jumpered to use 15 heads instead of 16. + * Some drives can be jumpered to use 4092 cyls instead of 16383. + */ + if ((id->cyls == 16383 + || (id->cyls == 4092 && id->cur_cyls == 16383)) && + id->sectors == 63 && + (id->heads == 15 || id->heads == 16) && + id->lba_capacity >= 16383*63*id->heads) + return 1; + + lba_sects = id->lba_capacity; + chs_sects = id->cyls * id->heads * id->sectors; + + /* perform a rough sanity check on lba_sects: within 10% is OK */ + if ((lba_sects - chs_sects) < chs_sects/10) + return 1; + + /* some drives have the word order reversed */ + head = ((lba_sects >> 16) & 0xffff); + tail = (lba_sects & 0xffff); + lba_sects = (head | (tail << 16)); + if ((lba_sects - chs_sects) < chs_sects/10) { + id->lba_capacity = lba_sects; + return 1; /* lba_capacity is (now) good */ + } + + return 0; /* lba_capacity value may be bad */ +} + +#ifndef __TASKFILE__IO + +/* + * read_intr() is the handler for disk read/multread interrupts + */ +static ide_startstop_t read_intr (ide_drive_t *drive) +{ + byte stat; + int i; + unsigned int msect, nsect; + struct request *rq; + + /* new way for dealing with premature shared PCI interrupts */ + if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { + if (stat & (ERR_STAT|DRQ_STAT)) { + return ide_error(drive, "read_intr", stat); + } + /* no data yet, so wait for another interrupt */ + ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); + return ide_started; + } + msect = drive->mult_count; + +read_next: + rq = HWGROUP(drive)->rq; + if (msect) { + if ((nsect = rq->current_nr_sectors) > msect) + nsect = msect; + msect -= nsect; + } else + nsect = 1; + idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); +#ifdef DEBUG + printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", + drive->name, rq->sector, rq->sector+nsect-1, + (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect); +#endif + rq->sector += nsect; + rq->buffer += nsect<<9; + rq->errors = 0; + i = (rq->nr_sectors -= nsect); + if (((long)(rq->current_nr_sectors -= nsect)) <= 0) + ide_end_request(1, HWGROUP(drive)); + if (i > 0) { + if (msect) + goto read_next; + ide_set_handler (drive, &read_intr, WAIT_CMD, NULL); + return ide_started; + } + return ide_stopped; +} + +/* + * write_intr() is the handler for disk write interrupts + */ +static ide_startstop_t write_intr (ide_drive_t *drive) +{ + byte stat; + int i; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = hwgroup->rq; + + if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { + printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat); + } else { +#ifdef DEBUG + printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", + drive->name, rq->sector, (unsigned long) rq->buffer, + rq->nr_sectors-1); +#endif + if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) { + rq->sector++; + rq->buffer += 512; + rq->errors = 0; + i = --rq->nr_sectors; + --rq->current_nr_sectors; + if (((long)rq->current_nr_sectors) <= 0) + ide_end_request(1, hwgroup); + if (i > 0) { + idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); + ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); + return ide_started; + } + return ide_stopped; + } + return ide_stopped; /* the original code did this here (?) */ + } + return ide_error(drive, "write_intr", stat); +} + +/* + * ide_multwrite() transfers a block of up to mcount sectors of data + * to a drive as part of a disk multiple-sector write operation. + * + * Returns 0 on success. + * + * Note that we may be called from two contexts - the do_rw_disk context + * and IRQ context. The IRQ can happen any time after we've output the + * full "mcount" number of sectors, so we must make sure we update the + * state _before_ we output the final part of the data! + */ +int ide_multwrite (ide_drive_t *drive, unsigned int mcount) +{ + ide_hwgroup_t *hwgroup= HWGROUP(drive); + struct request *rq = &hwgroup->wrq; + + do { + char *buffer; + int nsect = rq->current_nr_sectors; + + if (nsect > mcount) + nsect = mcount; + mcount -= nsect; + buffer = rq->buffer; + + rq->sector += nsect; + rq->buffer += nsect << 9; + rq->nr_sectors -= nsect; + rq->current_nr_sectors -= nsect; + + /* Do we move to the next bh after this? */ + if (!rq->current_nr_sectors) { + struct buffer_head *bh = rq->bh->b_reqnext; + + /* end early early we ran out of requests */ + if (!bh) { + mcount = 0; + } else { + rq->bh = bh; + rq->current_nr_sectors = bh->b_size >> 9; + rq->buffer = bh->b_data; + } + } + + /* + * Ok, we're all setup for the interrupt + * re-entering us on the last transfer. + */ + idedisk_output_data(drive, buffer, nsect<<7); + } while (mcount); + + return 0; +} + +/* + * multwrite_intr() is the handler for disk multwrite interrupts + */ +static ide_startstop_t multwrite_intr (ide_drive_t *drive) +{ + byte stat; + int i; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = &hwgroup->wrq; + + if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { + if (stat & DRQ_STAT) { + /* + * The drive wants data. Remember rq is the copy + * of the request + */ + if (rq->nr_sectors) { + if (ide_multwrite(drive, drive->mult_count)) + return ide_stopped; + ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); + return ide_started; + } + } else { + /* + * If the copy has all the blocks completed then + * we can end the original request. + */ + if (!rq->nr_sectors) { /* all done? */ + rq = hwgroup->rq; + for (i = rq->nr_sectors; i > 0;){ + i -= rq->current_nr_sectors; + ide_end_request(1, hwgroup); + } + return ide_stopped; + } + } + return ide_stopped; /* the original code did this here (?) */ + } + return ide_error(drive, "multwrite_intr", stat); +} +#endif /* __TASKFILE__IO */ + +#ifdef __TASKFILE__IO + +static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); +static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); +static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block); + +/* + * do_rw_disk() issues READ and WRITE commands to a disk, + * using LBA if supported, or CHS otherwise, to address sectors. + * It also takes care of issuing special DRIVE_CMDs. + */ +static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +{ + if (rq->cmd == READ) + goto good_command; + if (rq->cmd == WRITE) + goto good_command; + + printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); + ide_end_request(0, HWGROUP(drive)); + return ide_stopped; + +good_command: + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (IS_PDC4030_DRIVE) { + extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long); + return promise_rw_disk(drive, rq, block); + } +#endif /* CONFIG_BLK_DEV_PDC4030 */ + + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) /* 48-bit LBA */ + return lba_48_rw_disk(drive, rq, (unsigned long long) block); + if (drive->select.b.lba) /* 28-bit LBA */ + return lba_28_rw_disk(drive, rq, (unsigned long) block); + + /* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */ + return chs_rw_disk(drive, rq, (unsigned long) block); +} + +static task_ioreg_t get_command (ide_drive_t *drive, int cmd) +{ + int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0; + +#if 1 + lba48bit = drive->addressing; +#endif + + if ((cmd == READ) && (drive->using_dma)) + return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA; + else if ((cmd == READ) && (drive->mult_count)) + return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD; + else if (cmd == READ) + return (lba48bit) ? WIN_READ_EXT : WIN_READ; + else if ((cmd == WRITE) && (drive->using_dma)) + return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; + else if ((cmd == WRITE) && (drive->mult_count)) + return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; + else if (cmd == WRITE) + return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE; + else + return WIN_NOP; +} + +static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_task_t args; + + task_ioreg_t command = get_command(drive, rq->cmd); + unsigned int track = (block / drive->sect); + unsigned int sect = (block % drive->sect) + 1; + unsigned int head = (track % drive->head); + unsigned int cyl = (track / drive->head); + + memset(&taskfile, 0, sizeof(task_struct_t)); + memset(&hobfile, 0, sizeof(hob_struct_t)); + + taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; + taskfile.sector_number = sect; + taskfile.low_cylinder = cyl; + taskfile.high_cylinder = (cyl>>8); + taskfile.device_head = head; + taskfile.device_head |= drive->select.all; + taskfile.command = command; + +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); + if (lba) printk("LBAsect=%lld, ", block); + else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif + + memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); + memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); + args.command_type = ide_cmd_type_parser(&args); + args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); + args.handler = ide_handler_parser(&taskfile, &hobfile); + args.posthandler = NULL; + args.rq = (struct request *) rq; + args.block = block; + rq->special = NULL; + rq->special = (ide_task_t *)&args; + + return do_rw_taskfile(drive, &args); +} + +static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_task_t args; + + task_ioreg_t command = get_command(drive, rq->cmd); + + memset(&taskfile, 0, sizeof(task_struct_t)); + memset(&hobfile, 0, sizeof(hob_struct_t)); + + taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; + taskfile.sector_number = block; + taskfile.low_cylinder = (block>>=8); + taskfile.high_cylinder = (block>>=8); + taskfile.device_head = ((block>>8)&0x0f); + taskfile.device_head |= drive->select.all; + taskfile.command = command; + + +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); + if (lba) printk("LBAsect=%lld, ", block); + else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif + + memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); + memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); + args.command_type = ide_cmd_type_parser(&args); + args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); + args.handler = ide_handler_parser(&taskfile, &hobfile); + args.posthandler = NULL; + args.rq = (struct request *) rq; + args.block = block; + rq->special = NULL; + rq->special = (ide_task_t *)&args; + + return do_rw_taskfile(drive, &args); +} + +/* + * 268435455 == 137439 MB or 28bit limit + * 320173056 == 163929 MB or 48bit addressing + * 1073741822 == 549756 MB or 48bit addressing fake drive + */ + +static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_task_t args; + + task_ioreg_t command = get_command(drive, rq->cmd); + + memset(&taskfile, 0, sizeof(task_struct_t)); + memset(&hobfile, 0, sizeof(hob_struct_t)); + + taskfile.sector_count = rq->nr_sectors; + hobfile.sector_count = (rq->nr_sectors>>8); + + if (rq->nr_sectors == 65536) { + taskfile.sector_count = 0x00; + hobfile.sector_count = 0x00; + } + + taskfile.sector_number = block; /* low lba */ + taskfile.low_cylinder = (block>>=8); /* mid lba */ + taskfile.high_cylinder = (block>>=8); /* hi lba */ + hobfile.sector_number = (block>>=8); /* low lba */ + hobfile.low_cylinder = (block>>=8); /* mid lba */ + hobfile.high_cylinder = (block>>=8); /* hi lba */ + taskfile.device_head = drive->select.all; + hobfile.device_head = taskfile.device_head; + hobfile.control = (drive->ctl|0x80); + taskfile.command = command; + +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); + if (lba) printk("LBAsect=%lld, ", block); + else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif + + memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); + memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); + args.command_type = ide_cmd_type_parser(&args); + args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); + args.handler = ide_handler_parser(&taskfile, &hobfile); + args.posthandler = NULL; + args.rq = (struct request *) rq; + args.block = block; + rq->special = NULL; + rq->special = (ide_task_t *)&args; + + return do_rw_taskfile(drive, &args); +} + +#else /* !__TASKFILE__IO */ +/* + * do_rw_disk() issues READ and WRITE commands to a disk, + * using LBA if supported, or CHS otherwise, to address sectors. + * It also takes care of issuing special DRIVE_CMDs. + */ +static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +{ + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (drive->select.b.lba || IS_PDC4030_DRIVE) { +#else /* !CONFIG_BLK_DEV_PDC4030 */ + if (drive->select.b.lba) { +#endif /* CONFIG_BLK_DEV_PDC4030 */ + + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + task_ioreg_t tasklets[10]; + + tasklets[0] = 0; + tasklets[1] = 0; + tasklets[2] = rq->nr_sectors; + tasklets[3] = (rq->nr_sectors>>8); + if (rq->nr_sectors == 65536) { + tasklets[2] = 0x00; + tasklets[3] = 0x00; + } + tasklets[4] = (task_ioreg_t) block; + tasklets[5] = (task_ioreg_t) (block>>8); + tasklets[6] = (task_ioreg_t) (block>>16); + tasklets[7] = (task_ioreg_t) (block>>24); + tasklets[8] = (task_ioreg_t) 0; + tasklets[9] = (task_ioreg_t) 0; +// tasklets[8] = (task_ioreg_t) (block>>32); +// tasklets[9] = (task_ioreg_t) (block>>40); +#ifdef DEBUG + printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n", + drive->name, + (rq->cmd==READ)?"read":"writ", + block, + rq->nr_sectors, + (unsigned long) rq->buffer, + block); + printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", + drive->name, tasklets[3], tasklets[2], + tasklets[9], tasklets[8], tasklets[7], + tasklets[6], tasklets[5], tasklets[4]); +#endif + OUT_BYTE(tasklets[1], IDE_FEATURE_REG); + OUT_BYTE(tasklets[3], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[7], IDE_SECTOR_REG); + OUT_BYTE(tasklets[8], IDE_LCYL_REG); + OUT_BYTE(tasklets[9], IDE_HCYL_REG); + + OUT_BYTE(tasklets[0], IDE_FEATURE_REG); + OUT_BYTE(tasklets[2], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[4], IDE_SECTOR_REG); + OUT_BYTE(tasklets[5], IDE_LCYL_REG); + OUT_BYTE(tasklets[6], IDE_HCYL_REG); + OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG); + } else { +#ifdef DEBUG + printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n", + drive->name, (rq->cmd==READ)?"read":"writ", + block, rq->nr_sectors, (unsigned long) rq->buffer); +#endif + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); + OUT_BYTE(block,IDE_SECTOR_REG); + OUT_BYTE(block>>=8,IDE_LCYL_REG); + OUT_BYTE(block>>=8,IDE_HCYL_REG); + OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); + } + } else { + unsigned int sect,head,cyl,track; + track = block / drive->sect; + sect = block % drive->sect + 1; + OUT_BYTE(sect,IDE_SECTOR_REG); + head = track % drive->head; + cyl = track / drive->head; + + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); + OUT_BYTE(cyl,IDE_LCYL_REG); + OUT_BYTE(cyl>>8,IDE_HCYL_REG); + OUT_BYTE(head|drive->select.all,IDE_SELECT_REG); +#ifdef DEBUG + printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n", + drive->name, (rq->cmd==READ)?"read":"writ", cyl, + head, sect, rq->nr_sectors, (unsigned long) rq->buffer); +#endif + } +#ifdef CONFIG_BLK_DEV_PDC4030 + if (IS_PDC4030_DRIVE) { + extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *); + return do_pdc4030_io (drive, rq); + } +#endif /* CONFIG_BLK_DEV_PDC4030 */ + if (rq->cmd == READ) { +#ifdef CONFIG_BLK_DEV_IDEDMA + if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) + return ide_started; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG); + } else { + OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); + } + return ide_started; + } + if (rq->cmd == WRITE) { + ide_startstop_t startstop; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive))) + return ide_started; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG); + } else { + OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG); + } + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, + drive->mult_count ? "MULTWRITE" : "WRITE"); + return startstop; + } + if (!drive->unmask) + __cli(); /* local CPU only */ + if (drive->mult_count) { + ide_hwgroup_t *hwgroup = HWGROUP(drive); + /* + * Ugh.. this part looks ugly because we MUST set up + * the interrupt handler before outputting the first block + * of data to be written. If we hit an error (corrupted buffer list) + * in ide_multwrite(), then we need to remove the handler/timer + * before returning. Fortunately, this NEVER happens (right?). + * + * Except when you get an error it seems... + */ + hwgroup->wrq = *rq; /* scratchpad */ + ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL); + if (ide_multwrite(drive, drive->mult_count)) { + unsigned long flags; + spin_lock_irqsave(&io_request_lock, flags); + hwgroup->handler = NULL; + del_timer(&hwgroup->timer); + spin_unlock_irqrestore(&io_request_lock, flags); + return ide_stopped; + } + } else { + ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); + idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); + } + return ide_started; + } + printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); + ide_end_request(0, HWGROUP(drive)); + return ide_stopped; +} + +#endif /* __TASKFILE__IO */ + +static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive) +{ + MOD_INC_USE_COUNT; + if (drive->removable && drive->usage == 1) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.command = WIN_DOORLOCK; + check_disk_change(inode->i_rdev); + /* + * Ignore the return code from door_lock, + * since the open() has already succeeded, + * and the door_lock is irrelevant at this point. + */ + if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL)) + drive->doorlocking = 0; + } + return 0; +} + +static int do_idedisk_flushcache(ide_drive_t *drive); + +static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive) +{ + if (drive->removable && !drive->usage) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.command = WIN_DOORUNLOCK; + invalidate_bdev(inode->i_bdev, 0); + if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL)) + drive->doorlocking = 0; + } + if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) + if (do_idedisk_flushcache(drive)) + printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", + drive->name); + MOD_DEC_USE_COUNT; +} + +static int idedisk_media_change (ide_drive_t *drive) +{ + return drive->removable; /* if removable, always assume it was changed */ +} + +static void idedisk_revalidate (ide_drive_t *drive) +{ + grok_partitions(HWIF(drive)->gd, drive->select.b.unit, + 1< 0) of the drive, 0 if failed. + */ +static unsigned long idedisk_read_native_max_address(ide_drive_t *drive) +{ + ide_task_t args; + unsigned long addr = 0; + + if (!(drive->id->command_set_1 & 0x0400) && + !(drive->id->cfs_enable_2 & 0x0100)) + return addr; + + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX; + args.handler = task_no_data_intr; + + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + + /* if OK, compute maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) + | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) + | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) + | ((args.tfRegister[IDE_SECTOR_OFFSET] )); + } + addr++; /* since the return value is (maxlba - 1), we add 1 */ + return addr; +} + +static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive) +{ + ide_task_t args; + unsigned long long addr = 0; + + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT; + args.handler = task_no_data_intr; + + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + + /* if OK, compute maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) | + ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) | + (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); + u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | + ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | + (args.tfRegister[IDE_SECTOR_OFFSET]); + addr = ((__u64)high << 24) | low; + } + addr++; /* since the return value is (maxlba - 1), we add 1 */ + return addr; +} + +#ifdef CONFIG_IDEDISK_STROKE +/* + * Sets maximum virtual LBA address of the drive. + * Returns new maximum virtual LBA address (> 0) or 0 on failure. + */ +static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req) +{ + ide_task_t args; + unsigned long addr_set = 0; + + addr_req--; + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); + args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff); + args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff); + args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX; + args.handler = task_no_data_intr; + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + /* if OK, read new maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) + | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) + | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) + | ((args.tfRegister[IDE_SECTOR_OFFSET] )); + } + addr_set++; + return addr_set; +} + +static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req) +{ + ide_task_t args; + unsigned long long addr_set = 0; + + addr_req--; + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); + args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff); + args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff); + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT; + args.hobRegister[IDE_SECTOR_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); + args.hobRegister[IDE_LCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); + args.hobRegister[IDE_HCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); + args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40; + args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); + args.handler = task_no_data_intr; + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + /* if OK, compute maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) | + ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) | + (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); + u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | + ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | + (args.tfRegister[IDE_SECTOR_OFFSET]); + addr_set = ((__u64)high << 24) | low; + } + return addr_set; +} + +/* + * Tests if the drive supports Host Protected Area feature. + * Returns true if supported, false otherwise. + */ +static inline int idedisk_supports_host_protected_area(ide_drive_t *drive) +{ + int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0; + printk("%s: host protected area => %d\n", drive->name, flag); + return flag; +} + +#endif /* CONFIG_IDEDISK_STROKE */ + +/* + * Compute drive->capacity, the full capacity of the drive + * Called with drive->id != NULL. + * + * To compute capacity, this uses either of + * + * 1. CHS value set by user (whatever user sets will be trusted) + * 2. LBA value from target drive (require new ATA feature) + * 3. LBA value from system BIOS (new one is OK, old one may break) + * 4. CHS value from system BIOS (traditional style) + * + * in above order (i.e., if value of higher priority is available, + * reset will be ignored). + */ +static void init_idedisk_capacity (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + unsigned long capacity = drive->cyl * drive->head * drive->sect; + unsigned long set_max = idedisk_read_native_max_address(drive); + unsigned long long capacity_2 = capacity; + unsigned long long set_max_ext; + + drive->capacity48 = 0; + drive->select.b.lba = 0; + + if (id->cfs_enable_2 & 0x0400) { + capacity_2 = id->lba_capacity_2; + drive->head = drive->bios_head = 255; + drive->sect = drive->bios_sect = 63; + drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect); + drive->select.b.lba = 1; + set_max_ext = idedisk_read_native_max_address_ext(drive); + if (set_max_ext > capacity_2) { +#ifdef CONFIG_IDEDISK_STROKE + set_max_ext = idedisk_read_native_max_address_ext(drive); + set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext); + if (set_max_ext) { + drive->capacity48 = capacity_2 = set_max_ext; + drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect); + drive->select.b.lba = 1; + drive->id->lba_capacity_2 = capacity_2; + } +#else /* !CONFIG_IDEDISK_STROKE */ + printk("%s: setmax_ext LBA %llu, native %llu\n", + drive->name, set_max_ext, capacity_2); +#endif /* CONFIG_IDEDISK_STROKE */ + } + drive->bios_cyl = drive->cyl; + drive->capacity48 = capacity_2; + drive->capacity = (unsigned long) capacity_2; + return; + /* Determine capacity, and use LBA if the drive properly supports it */ + } else if ((id->capability & 2) && lba_capacity_is_ok(id)) { + capacity = id->lba_capacity; + drive->cyl = capacity / (drive->head * drive->sect); + drive->select.b.lba = 1; + } + + if (set_max > capacity) { +#ifdef CONFIG_IDEDISK_STROKE + set_max = idedisk_read_native_max_address(drive); + set_max = idedisk_set_max_address(drive, set_max); + if (set_max) { + drive->capacity = capacity = set_max; + drive->cyl = set_max / (drive->head * drive->sect); + drive->select.b.lba = 1; + drive->id->lba_capacity = capacity; + } +#else /* !CONFIG_IDEDISK_STROKE */ + printk("%s: setmax LBA %lu, native %lu\n", + drive->name, set_max, capacity); +#endif /* CONFIG_IDEDISK_STROKE */ + } + + drive->capacity = capacity; + + if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { + drive->capacity48 = id->lba_capacity_2; + drive->head = 255; + drive->sect = 63; + drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect); + } +} + +static unsigned long idedisk_capacity (ide_drive_t *drive) +{ + if (drive->id->cfs_enable_2 & 0x0400) + return (drive->capacity48 - drive->sect0); + return (drive->capacity - drive->sect0); +} + +static ide_startstop_t idedisk_special (ide_drive_t *drive) +{ + special_t *s = &drive->special; + + if (s->b.set_geometry) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_handler_t *handler = NULL; + + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + + s->b.set_geometry = 0; + taskfile.sector_number = drive->sect; + taskfile.low_cylinder = drive->cyl; + taskfile.high_cylinder = drive->cyl>>8; + taskfile.device_head = ((drive->head-1)|drive->select.all)&0xBF; + if (!IS_PDC4030_DRIVE) { + taskfile.sector_count = drive->sect; + taskfile.command = WIN_SPECIFY; + handler = ide_handler_parser(&taskfile, &hobfile); + } + do_taskfile(drive, &taskfile, &hobfile, handler); + } else if (s->b.recalibrate) { + s->b.recalibrate = 0; + if (!IS_PDC4030_DRIVE) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.sector_count = drive->sect; + taskfile.command = WIN_RESTORE; + do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + } + } else if (s->b.set_multmode) { + s->b.set_multmode = 0; + if (drive->id && drive->mult_req > drive->id->max_multsect) + drive->mult_req = drive->id->max_multsect; + if (!IS_PDC4030_DRIVE) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.sector_count = drive->mult_req; + taskfile.command = WIN_SETMULT; + do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + } + } else if (s->all) { + int special = s->all; + s->all = 0; + printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special); + return ide_stopped; + } + return IS_PDC4030_DRIVE ? ide_stopped : ide_started; +} + +static void idedisk_pre_reset (ide_drive_t *drive) +{ + int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1; + + drive->special.all = 0; + drive->special.b.set_geometry = legacy; + drive->special.b.recalibrate = legacy; + if (OK_TO_RESET_CONTROLLER) + drive->mult_count = 0; + if (!drive->keep_settings && !drive->using_dma) + drive->mult_req = 0; + if (drive->mult_req != drive->mult_count) + drive->special.b.set_multmode = 1; +} + +#ifdef CONFIG_PROC_FS + +static int smart_enable(ide_drive_t *drive) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = SMART_ENABLE; + taskfile.low_cylinder = SMART_LCYL_PASS; + taskfile.high_cylinder = SMART_HCYL_PASS; + taskfile.command = WIN_SMART; + return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); +} + +static int get_smart_values(ide_drive_t *drive, byte *buf) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = SMART_READ_VALUES; + taskfile.sector_count = 0x01; + taskfile.low_cylinder = SMART_LCYL_PASS; + taskfile.high_cylinder = SMART_HCYL_PASS; + taskfile.command = WIN_SMART; + (void) smart_enable(drive); + return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); +} + +static int get_smart_thresholds(ide_drive_t *drive, byte *buf) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = SMART_READ_THRESHOLDS; + taskfile.sector_count = 0x01; + taskfile.low_cylinder = SMART_LCYL_PASS; + taskfile.high_cylinder = SMART_HCYL_PASS; + taskfile.command = WIN_SMART; + (void) smart_enable(drive); + return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); +} + +static int proc_idedisk_read_cache + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + char *out = page; + int len; + + if (drive->id) + len = sprintf(out,"%i\n", drive->id->buf_size / 2); + else + len = sprintf(out,"(none)\n"); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_idedisk_read_smart_thresholds + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *)data; + int len = 0, i = 0; + + if (!get_smart_thresholds(drive, page)) { + unsigned short *val = (unsigned short *) page; + char *out = ((char *)val) + (SECTOR_WORDS * 4); + page = out; + do { + out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); + val += 1; + } while (i < (SECTOR_WORDS * 2)); + len = out - page; + } + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_idedisk_read_smart_values + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *)data; + int len = 0, i = 0; + + if (!get_smart_values(drive, page)) { + unsigned short *val = (unsigned short *) page; + char *out = ((char *)val) + (SECTOR_WORDS * 4); + page = out; + do { + out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); + val += 1; + } while (i < (SECTOR_WORDS * 2)); + len = out - page; + } + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static ide_proc_entry_t idedisk_proc[] = { + { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL }, + { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL }, + { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_smart_values, NULL }, + { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_smart_thresholds, NULL }, + { NULL, 0, NULL, NULL } +}; + +#else + +#define idedisk_proc NULL + +#endif /* CONFIG_PROC_FS */ + +static int set_multcount(ide_drive_t *drive, int arg) +{ +#ifdef __TASKFILE__IO + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + + if (drive->special.b.set_multmode) + return -EBUSY; + + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.sector_count = drive->mult_req; + taskfile.command = WIN_SETMULT; + drive->mult_req = arg; + drive->special.b.set_multmode = 1; + ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); +#else /* !__TASKFILE__IO */ + struct request rq; + + if (drive->special.b.set_multmode) + return -EBUSY; + ide_init_drive_cmd (&rq); + rq.cmd = IDE_DRIVE_CMD; + drive->mult_req = arg; + drive->special.b.set_multmode = 1; + (void) ide_do_drive_cmd (drive, &rq, ide_wait); +#endif /* __TASKFILE__IO */ + return (drive->mult_count == arg) ? 0 : -EIO; +} + +static int set_nowerr(ide_drive_t *drive, int arg) +{ + if (ide_spin_wait_hwgroup(drive)) + return -EBUSY; + drive->nowerr = arg; + drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; + spin_unlock_irq(&io_request_lock); + return 0; +} + +static int write_cache (ide_drive_t *drive, int arg) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; + taskfile.command = WIN_SETFEATURES; + + if (!(drive->id->cfs_enable_2 & 0x3000)) + return 1; + + (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + drive->wcache = arg; + return 0; +} + +static int do_idedisk_standby (ide_drive_t *drive) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.command = WIN_STANDBYNOW1; + return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); +} + +static int do_idedisk_flushcache (ide_drive_t *drive) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + if (drive->id->cfs_enable_2 & 0x2400) { + taskfile.command = WIN_FLUSH_CACHE_EXT; + } else { + taskfile.command = WIN_FLUSH_CACHE; + } + return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); +} + +static int set_acoustic (ide_drive_t *drive, int arg) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + + taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM; + taskfile.sector_count = arg; + + taskfile.command = WIN_SETFEATURES; + (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + drive->acoustic = arg; + return 0; +} + +static int probe_lba_addressing (ide_drive_t *drive, int arg) +{ + drive->addressing = 0; + + if (!(drive->id->cfs_enable_2 & 0x0400)) + return -EIO; + + drive->addressing = arg; + return 0; +} + +static int set_lba_addressing (ide_drive_t *drive, int arg) +{ + return (probe_lba_addressing(drive, arg)); +} + +static void idedisk_add_settings(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; +#if 0 + int major = HWIF(drive)->major; + int minor = drive->select.b.unit << PARTN_BITS; +#endif + + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); + ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); + ide_add_setting(drive, "address", SETTING_RW, HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, TYPE_INTA, 0, 2, 1, 1, &drive->addressing, set_lba_addressing); + ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); + ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 1, &drive->mult_count, set_multcount); + ide_add_setting(drive, "nowerr", SETTING_RW, HDIO_GET_NOWERR, HDIO_SET_NOWERR, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr); +#if 0 + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 1, &read_ahead[major], NULL); + ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, 4096, PAGE_SIZE, 1024, &max_readahead[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 1, &max_sectors[major][minor], NULL); +#endif + ide_add_setting(drive, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL); + ide_add_setting(drive, "wcache", SETTING_RW, HDIO_GET_WCACHE, HDIO_SET_WCACHE, TYPE_BYTE, 0, 1, 1, 1, &drive->wcache, write_cache); + ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic); + ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL); + ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); +} + +static void idedisk_setup (ide_drive_t *drive) +{ + int i; + + struct hd_driveid *id = drive->id; + unsigned long capacity; + + idedisk_add_settings(drive); + + if (id == NULL) + return; + + /* + * CompactFlash cards and their brethern look just like hard drives + * to us, but they are removable and don't have a doorlock mechanism. + */ + if (drive->removable && !drive_is_flashcard(drive)) { + /* + * Removable disks (eg. SYQUEST); ignore 'WD' drives + */ + if (id->model[0] != 'W' || id->model[1] != 'D') { + drive->doorlocking = 1; + } + } + for (i = 0; i < MAX_DRIVES; ++i) { + ide_hwif_t *hwif = HWIF(drive); + + if (drive != &hwif->drives[i]) continue; +#ifdef DEVFS_MUST_DIE + hwif->gd->de_arr[i] = drive->de; +#endif + if (drive->removable) + hwif->gd->flags[i] |= GENHD_FL_REMOVABLE; + break; + } + + /* Extract geometry if we did not already have one for the drive */ + if (!drive->cyl || !drive->head || !drive->sect) { + drive->cyl = drive->bios_cyl = id->cyls; + drive->head = drive->bios_head = id->heads; + drive->sect = drive->bios_sect = id->sectors; + } + + /* Handle logical geometry translation by the drive */ + if ((id->field_valid & 1) && id->cur_cyls && + id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) { + drive->cyl = id->cur_cyls; + drive->head = id->cur_heads; + drive->sect = id->cur_sectors; + } + + /* Use physical geometry if what we have still makes no sense */ + if (drive->head > 16 && id->heads && id->heads <= 16) { + drive->cyl = id->cyls; + drive->head = id->heads; + drive->sect = id->sectors; + } + + /* calculate drive capacity, and select LBA if possible */ + init_idedisk_capacity (drive); + + /* + * if possible, give fdisk access to more of the drive, + * by correcting bios_cyls: + */ + capacity = idedisk_capacity (drive); + if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) && + (!drive->forced_geom) && drive->bios_sect && drive->bios_head) + drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head; + printk (KERN_INFO "XEN %s: %ld sectors", drive->name, capacity); + + /* Give size in megabytes (MB), not mebibytes (MiB). */ + /* We compute the exact rounded value, avoiding overflow. */ + printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950); + + /* Only print cache size when it was specified */ + if (id->buf_size) + printk (" w/%dKiB Cache", id->buf_size/2); + + printk(", CHS=%d/%d/%d", + drive->bios_cyl, drive->bios_head, drive->bios_sect); +#ifdef CONFIG_BLK_DEV_IDEDMA + if (drive->using_dma) + (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + printk("\n"); + + drive->mult_count = 0; + if (id->max_multsect) { +#ifdef CONFIG_IDEDISK_MULTI_MODE + id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; + id->multsect_valid = id->multsect ? 1 : 0; + drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; + drive->special.b.set_multmode = drive->mult_req ? 1 : 0; +#else /* original, pre IDE-NFG, per request of AC */ + drive->mult_req = INITIAL_MULT_COUNT; + if (drive->mult_req > id->max_multsect) + drive->mult_req = id->max_multsect; + if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) + drive->special.b.set_multmode = 1; +#endif /* CONFIG_IDEDISK_MULTI_MODE */ + } + drive->no_io_32bit = id->dword_io ? 1 : 0; + if (drive->id->cfs_enable_2 & 0x3000) + write_cache(drive, (id->cfs_enable_2 & 0x3000)); + (void) probe_lba_addressing(drive, 1); +} + +static int idedisk_cleanup (ide_drive_t *drive) +{ + if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) + if (do_idedisk_flushcache(drive)) + printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", + drive->name); + return ide_unregister_subdriver(drive); +} + +int idedisk_reinit(ide_drive_t *drive); + +/* + * IDE subdriver functions, registered with ide.c + */ +static ide_driver_t idedisk_driver = { + name: "ide-disk", + version: IDEDISK_VERSION, + media: ide_disk, + busy: 0, + supports_dma: 1, + supports_dsc_overlap: 0, + cleanup: idedisk_cleanup, + standby: do_idedisk_standby, + flushcache: do_idedisk_flushcache, + do_request: do_rw_disk, + end_request: NULL, + ioctl: NULL, + open: idedisk_open, + release: idedisk_release, + media_change: idedisk_media_change, + revalidate: idedisk_revalidate, + pre_reset: idedisk_pre_reset, + capacity: idedisk_capacity, + special: idedisk_special, + /*proc: idedisk_proc,*/ + reinit: idedisk_reinit, + ata_prebuilder: NULL, + atapi_prebuilder: NULL, +}; + +int idedisk_init (void); +static ide_module_t idedisk_module = { + IDE_DRIVER_MODULE, + idedisk_init, + &idedisk_driver, + NULL +}; + +MODULE_DESCRIPTION("ATA DISK Driver"); + +int idedisk_reinit (ide_drive_t *drive) +{ + int failed = 0; + + MOD_INC_USE_COUNT; + + if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); + return 1; + } + DRIVER(drive)->busy++; + idedisk_setup(drive); + if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { + printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); + (void) idedisk_cleanup(drive); + DRIVER(drive)->busy--; + return 1; + } + DRIVER(drive)->busy--; + failed--; + + ide_register_module(&idedisk_module); + MOD_DEC_USE_COUNT; + return 0; +} + +static void __exit idedisk_exit (void) +{ + ide_drive_t *drive; + int failed = 0; + + while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) { + if (idedisk_cleanup (drive)) { + printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); + failed++; + } + /* We must remove proc entries defined in this module. + Otherwise we oops while accessing these entries */ +#ifdef CONFIG_PROC_FS + if (drive->proc) + ide_remove_proc_entries(drive->proc, idedisk_proc); +#endif + } + ide_unregister_module(&idedisk_module); +} + +int idedisk_init (void) +{ + ide_drive_t *drive; + int failed = 0; + + MOD_INC_USE_COUNT; + while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) { + if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); + continue; + } + DRIVER(drive)->busy++; + idedisk_setup(drive); + if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { + printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); + (void) idedisk_cleanup(drive); + DRIVER(drive)->busy--; + continue; + } + DRIVER(drive)->busy--; + failed--; + } + ide_register_module(&idedisk_module); + MOD_DEC_USE_COUNT; + return 0; +} + +module_init(idedisk_init); +module_exit(idedisk_exit); +MODULE_LICENSE("GPL"); diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c new file mode 100644 index 0000000000..0416b467a7 --- /dev/null +++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c @@ -0,0 +1,827 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include /* HDIO_GETGEO, et al */ +#include +#include + +/* NOTE: this is drive independent, so no inclusion of ide.h */ + +#include +#include +#include +#include /* put_user() */ + +#define MAJOR_NR XLBLK_MAJOR /* force defns in blk.h, must preceed include */ +static int xlblk_major = XLBLK_MAJOR; + +#include /* must come after definition of MAJOR_NR!! */ + +/* instead of including linux/ide.h to pick up the definitiong of byte + * (and consequently screwing up blk.h, we'll just copy the definition */ +typedef unsigned char byte; + +void xlblk_ide_register_disk(int, unsigned long); + +#define XLBLK_MAX 2 /* very arbitrary */ +#define XLBLK_MAJOR_NAME "blk" +#define IDE_PARTN_BITS 6 /* from ide.h::PARTN_BITS */ +#define IDE_PARTN_MASK ((1<i_rdev); + if (minor_dev >= XLBLK_MAX) return -ENODEV; + + if (XLBLK_DEBUG_IOCTL) + { + printk (KERN_ALERT + " command: 0x%x, argument: 0x%lx, minor: 0x%x\n", + command, (long) argument, minor_dev); + } + + switch (command) + { + case BLKGETSIZE : + { + if (XLBLK_DEBUG_IOCTL) + { + printk (KERN_ALERT + " BLKGETSIZE: %x %lx\n", BLKGETSIZE, + (long) xen_disk_info.disks[0].capacity); + } + return put_user(xen_disk_info.disks[0].capacity, + (unsigned long *) argument); + } + case BLKRRPART : + { + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " BLKRRPART: %x\n", BLKRRPART); } + break; + } + case BLKSSZGET : + { + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " BLKSSZGET: %x 0x%x\n", BLKSSZGET, + xlblk_hardsect_size[minor_dev]); } + return xlblk_hardsect_size[minor_dev]; + } + case HDIO_GETGEO : + { + struct hd_geometry *geo = (struct hd_geometry *)argument; + + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " HDIO_GETGEO: %x\n", HDIO_GETGEO); } + + if (!argument) return -EINVAL; + /* + if (put_user(0x80, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x20b, (unsigned short *) &geo->cylinders)) return -EFAULT; + */ + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x106, (unsigned short *) &geo->cylinders)) return -EFAULT; + + return 0; + } + case HDIO_GETGEO_BIG : + { + struct hd_big_geometry *geo = (struct hd_big_geometry *) argument; + + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG); } + + if (!argument) return -EINVAL; + /* + if (put_user(0x80, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x20b, (unsigned int *) &geo->cylinders)) return -EFAULT; + */ + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT; + + return 0; + } + default : + { + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " eh? unknown ioctl\n"); } + break; + } + } + + return 0; +} + +static int xenolinux_block_check(kdev_t dev) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xenolinux_block_check\n"); } + return 0; +} + +static int xenolinux_block_revalidate(kdev_t dev) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xenolinux_block_revalidate\n"); } + return 0; +} + +/* + * hypervisor_request + * + * request block io + * + * id: for guest use only. + * operation: XEN_BLOCK_READ, XEN_BLOCK_WRITE or XEN_BLOCK_PROBE + * buffer: buffer to read/write into. this should be a + * virtual address in the guest os. + * block_number: block to read + * block_size: size of each block + * device: ide/hda is 768 or 0x300 + * mode: XEN_BLOCK_SYNC or XEN_BLOCK_ASYNC. async requests + * will queue until a sync request is issued. + */ + +void hypervisor_request(void * id, + int operation, + char * buffer, + unsigned long block_number, + unsigned short block_size, + kdev_t device, + int mode) +{ + blk_ring_t *blk_ring = start_info.blk_ring; + int position; + void *buffer_pa, *buffer_ma; + kdev_t phys_device = (kdev_t) 0; + unsigned long sector_number = 0; + +#if 0 + printk(KERN_ALERT "[%x]", id); + printk (KERN_ALERT + "xlblk_req: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n", + id, operation, buffer, block_number, block_size, device); +#endif + + /* XXX SMH: now need to convert guest virtual address to machine address */ + buffer_pa = (void *)virt_to_phys((unsigned long)buffer); + buffer_ma = (void *)phys_to_machine((unsigned long)buffer_pa); + +#if 0 + printk(KERN_ALERT "va %p => pa %p => ma %p\n", buffer, buffer_pa, buffer_ma); +#endif + + if (operation == XEN_BLOCK_PROBE) + { + phys_device = (kdev_t) 0; + sector_number = 0; + } + else if (operation == XEN_BLOCK_READ || operation == XEN_BLOCK_WRITE) + { + /* + * map logial major device to the physical device number + * + * XLBLK_MAJOR -> IDE0_MAJOR (123 -> 3) + */ + if (MAJOR(device) == XLBLK_MAJOR) + { + phys_device = MKDEV(IDE0_MAJOR, 0); + } + else + { + printk (KERN_ALERT + "error: xl_block::hypervisor_request: unknown device [0x%x]\n", + device); + BUG(); + } + + /* + * compute real buffer location on disk + * (from ll_rw_block.c::submit_bh) + */ + { + int idx = 0; + + struct gendisk *gd = (struct gendisk *) xen_disk_info.disks[idx].gendisk; + unsigned int minor = MINOR(device); + + sector_number = block_number /* * block_size >> 9 */; + + if (gd != NULL) /* if we have a partition table... */ + { + sector_number += gd->part[minor & IDE_PARTN_MASK].start_sect; + } + } + } + + /* + * CHECK TO SEE IF THERE IS SPACE IN THE RING + */ + if (BLK_TX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons) + { + printk (KERN_ALERT "hypervisor_request: tx_cons: %d, tx_prod:%d", + blk_ring->tx_cons, blk_ring->tx_prod); + } + + /* fill out a communications ring structure + and then trap into the hypervisor */ + position = blk_ring->tx_prod; + blk_ring->tx_ring[position].id = id; + blk_ring->tx_ring[position].priority = mode; + blk_ring->tx_ring[position].operation = operation; + blk_ring->tx_ring[position].buffer = buffer_ma; + blk_ring->tx_ring[position].block_number = block_number; + blk_ring->tx_ring[position].block_size = block_size; + blk_ring->tx_ring[position].device = phys_device; + blk_ring->tx_ring[position].sector_number = sector_number; + + blk_ring->tx_prod = BLK_TX_RING_INC(blk_ring->tx_prod); + + if (mode == XEN_BLOCK_SYNC) + { + /* trap into hypervisor */ + HYPERVISOR_block_io_op(); + } + else if (mode == XEN_BLOCK_ASYNC) + { + /* for now, do nothing. the request will go in the ring and + the next sync request will trigger the hypervisor to act */ + } + else + { + /* ummm, unknown mode. */ + BUG(); + } + + return; +} + + +/* + * do_xlblk_request + * + * read a block; request is in a request queue + * + * TO DO: should probably release the io_request_lock and then re-acquire + * (see LDD p. 338) + */ + +static void do_xlblk_request (request_queue_t *rq) +{ + struct request *req; + + if (XLBLK_DEBUG) + { + printk (KERN_ALERT "xlblk.c::do_xlblk_request for '%s'\n", DEVICE_NAME); + } + + while (!QUEUE_EMPTY) + { + struct buffer_head *bh; + unsigned long offset; + unsigned long length; + int rw; + + req = CURRENT; + + if (XLBLK_DEBUG) + { + printk (KERN_ALERT + "do_xlblk_request %p: cmd %i, sec %lx, (%li) bh:%p\n", + req, req->cmd, req->sector, + req->current_nr_sectors, req->bh); + } + + /* is there space in the tx ring for this request? + * if the ring is full, then leave the request in the queue + * + * THIS IS A BIT BOGUS SINCE XEN COULD BE UPDATING TX_CONS + * AT THE SAME TIME + */ + { + blk_ring_t *blk_ring = start_info.blk_ring; + + if (BLK_RX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons) + { + printk (KERN_ALERT "OOPS, TX LOOKS FULL cons: %d prod: %d\n", + blk_ring->tx_cons, blk_ring->tx_prod); + break; + } + } + + req->errors = 0; + blkdev_dequeue_request(req); + + bh = req->bh; + + while (bh) + { + + offset = bh->b_rsector << 9; + length = bh->b_size; + + rw = req->cmd; + if (rw == READA) rw= READ; + if ((rw != READ) && (rw != WRITE)) + { + printk (KERN_ALERT + "XenoLinux Virtual Block Device: bad command: %d\n", rw); + BUG(); + } + + /* + if (XLBLK_DEBUG) + { + printk (KERN_ALERT "xlblk.c::do_xlblk_request\n"); + printk (KERN_ALERT " b_blocknr: 0x%lx %ld\n", + bh->b_blocknr, bh->b_blocknr); + printk (KERN_ALERT " b_size: 0x%x %d\n", bh->b_size, bh->b_size); + printk (KERN_ALERT " b_dev: 0x%x %d\n", bh->b_dev, bh->b_dev); + printk (KERN_ALERT " b_rsector: 0x%lx %ld\n", + bh->b_rsector, bh->b_rsector); + } + */ + + hypervisor_request (req, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, + bh->b_data, bh->b_rsector, bh->b_size, + bh->b_dev, XEN_BLOCK_SYNC); + + bh = bh->b_reqnext; + } + } + + return; +} + +/* + * xenolinux_block_request + * + * read a block without using a request queue + */ + +static int xenolinux_block_request(request_queue_t *rq, + int rw, + struct buffer_head *bh) +{ + unsigned int minor; + unsigned long offset; + unsigned long length; + + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xlblk.c::xenolinux_block_request: %lx %d %lx\n", + (unsigned long) rq, rw, (unsigned long) bh); } + /* + printk (KERN_ALERT "xlblk.c::xlblk_request: op:%d bh:%p sect:%lu sz:%u\n", + rw, bh, bh->b_rsector, bh->b_size); + */ + + minor = MINOR(bh->b_rdev); + + offset = bh->b_rsector << 9; + length = bh->b_size; + + if (rw == READA) rw= READ; + if ((rw != READ) && (rw != WRITE)) + { + printk (KERN_ALERT + "XenoLinux Virtual Block Device: bad command: %d\n", rw); + goto fail; + } + + hypervisor_request (bh, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, + bh->b_data, bh->b_rsector, bh->b_size, + bh->b_dev, XEN_BLOCK_SYNC); + + return 0; + + fail: + return 0; +} + +static struct block_device_operations xenolinux_block_fops = +{ + open: xenolinux_block_open, + release: xenolinux_block_release, + ioctl: xenolinux_block_ioctl, + check_media_change: xenolinux_block_check, + revalidate: xenolinux_block_revalidate, +}; + +static void xlblk_rx_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + xlblk_device_t *dev = (xlblk_device_t *)dev_id; + blk_ring_t *blk_ring = start_info.blk_ring; + struct buffer_head *bh; + struct request *req; + int loop; + + for (loop = blk_ring->rx_cons; + loop != blk_ring->rx_prod; + loop = BLK_RX_RING_INC(loop)) + { + blk_ring_entry_t *bret = &blk_ring->rx_ring[loop]; + void *buffer_pa, *buffer_va; + + buffer_pa = machine_to_phys((unsigned long)bret->buffer); + buffer_va = phys_to_virt((unsigned long)buffer_pa); + +#if 0 + printk(KERN_ALERT "xlblk_rx_int: buffer ma %p => pa %p => va %p\n", + bret->buffer, buffer_pa, buffer_va); + + + if (XLBLK_DEBUG) + { + printk (KERN_ALERT + "xlblock::xlblk_rx_int [%s]\n", + (bret->operation == XEN_BLOCK_READ) ? "read" : "write"); + printk (KERN_ALERT + " vbuf: %lx, pbuf: %lx, blockno: %lx, size: %x, device %x\n", + (unsigned long) buffer_va, (unsigned long) bret->buffer, + bret->block_number, bret->block_size, bret->device); + printk (KERN_ALERT " bret: %p bh: %p\n", bret, bret->id); + } + + /* + printk (KERN_ALERT + "xlblk_rx: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n", + bret->id, bret->operation, bret->buffer, bret->block_number, + bret->block_size, bret->device); + */ +#endif + + if (USE_REQUEST_QUEUE) + { + req = (struct request *)bret->id; + printk(KERN_ALERT "|%x|", req); + + if (!end_that_request_first(req, 1, "NAME")) + { + blkdev_dequeue_request(req); + + /* should be end_that_request_last(req) + to wake up waiting processes (with complete) */ + blkdev_release_request(req); + } + + /* + if (XLBLK_DEBUG) + { + int temp; + printk(KERN_ALERT + "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n", + vbuffer, bret->block_number, bret->block_size, bret->device, + bh->b_end_io); + + for (temp = 0; temp < bret->block_size; temp++) + { + if (temp % 16 == 0) printk ("[%4x] ", temp); + else if (temp % 4 == 0) printk (" "); + printk ("%02x", + vbuffer[temp] & 255); + if ((temp + 1) % 16 == 0) printk ("\n"); + } + printk ("\n\n"); + } + */ + +#ifdef BOGUS + req = (struct request *)bret->id; + while ((bh = req->bh) != NULL) + { + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh,1); + } + blkdev_release_request(req); +#endif /* BOGUS */ + } + else + { + bh = (struct buffer_head *)bret->id; + bh->b_end_io(bh,1); + + /* + if (XLBLK_DEBUG) + { + int temp; +#if 0 + printk(KERN_ALERT + "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n", + vbuffer, bret->block_number, bret->block_size, bret->device, + bh->b_end_io); +#endif + + for (temp = 0; temp < bret->block_size; temp++) + { + if (temp % 16 == 0) printk ("[%4x] ", temp); + else if (temp % 4 == 0) printk (" "); + printk ("%02x", + vbuffer[temp] & 255); + if ((temp + 1) % 16 == 0) printk ("\n"); + } + printk ("\n\n"); + } + */ + } + } + + blk_ring->rx_cons = loop; +} + +static void xlblk_tx_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "--- xlblock::xlblk_tx_int\n"); } +} + +int __init xlblk_init(void) +{ + blk_ring_t *blk_ring = start_info.blk_ring; + int loop, error, result; + + /* + * initialize memory rings to communicate with hypervisor + */ + + if ( blk_ring == NULL ) return -ENOMEM; + + blk_ring->tx_prod = blk_ring->tx_cons = 0; + blk_ring->rx_prod = blk_ring->rx_cons = 0; + blk_ring->tx_ring = NULL; + blk_ring->rx_ring = NULL; + + blk_ring->tx_ring = kmalloc(BLK_TX_RING_SIZE * sizeof(blk_ring_entry_t), + GFP_KERNEL); + blk_ring->rx_ring = kmalloc(BLK_RX_RING_SIZE * sizeof(blk_ring_entry_t), + GFP_KERNEL); + + if ((blk_ring->tx_ring == NULL) || + (blk_ring->rx_ring == NULL)) + { + printk (KERN_ALERT + "error, could not allocate ring memory for block device\n"); + error = -ENOBUFS; + goto fail; + } + + /* + * setup soft interrupts to communicate with hypervisor + */ + + error = request_irq(XLBLK_RX_IRQ, xlblk_rx_int, 0, "xlblk-rx", + &xlblk_device); + if (error) + { + printk(KERN_ALERT "Could not allocate receive interrupt\n"); + goto fail; + } + + error = request_irq(XLBLK_TX_IRQ, xlblk_tx_int, 0, "xlblk-tx", + &xlblk_device); + if (error) + { + printk(KERN_ALERT "Could not allocate transmit interrupt\n"); + free_irq(XLBLK_RX_IRQ, &xlblk_device); + goto fail; + } + + /* + * get information about physical drives + * + */ + { + /* NOTE: this should only occur in domain 0 */ + memset (&xen_disk_info, 0, sizeof(xen_disk_info)); + xen_disk_info.count = 0; + + hypervisor_request(NULL, XEN_BLOCK_PROBE, (char *) &xen_disk_info, + 0, 0, (kdev_t) 0, XEN_BLOCK_SYNC); + + { + int loop; + for (loop = 0; loop < xen_disk_info.count; loop++) + { + printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n", + loop, xen_disk_info.disks[loop].type, + xen_disk_info.disks[loop].capacity); + } + } + } + + /* + * initialize device driver + */ + + SET_MODULE_OWNER(&xenolinux_block_fops); + + result = register_blkdev(xlblk_major, "block", &xenolinux_block_fops); + if (result < 0) + { + printk (KERN_ALERT "xenolinux block: can't get major %d\n", xlblk_major); + return result; + } + + /* initialize global arrays in drivers/block/ll_rw_block.c */ + blk_size[xlblk_major] = xlblk_blk_size; + blksize_size[xlblk_major] = xlblk_blksize_size; + hardsect_size[xlblk_major] = xlblk_hardsect_size; + read_ahead[xlblk_major] = xlblk_read_ahead; + max_sectors[xlblk_major] = xlblk_max_sectors; + for (loop = 0; loop < XLBLK_MAX; loop++) + { + xlblk_blk_size[loop] = xen_disk_info.disks[0].capacity; + xlblk_blksize_size[loop] = 512; + xlblk_hardsect_size[loop] = 512; + xlblk_read_ahead[loop] = 8; + xlblk_max_sectors[loop] = 128; + } + + if (USE_REQUEST_QUEUE) + { + /* NEED TO MODIFY THIS TO HANDLE MULTIPLE QUEUES + * also, should replace do_xlblk_request with blk.h::DEVICE_REQUEST + */ + blk_init_queue(BLK_DEFAULT_QUEUE(xlblk_major), do_xlblk_request); + blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0); + } + else + { + /* we don't use __make_request in ll_rw_blk */ + blk_queue_make_request(BLK_DEFAULT_QUEUE(xlblk_major), + xenolinux_block_request); + } + xlblk_ide_register_disk(0, xen_disk_info.disks[0].capacity); + + /* + * completion + */ + printk(KERN_ALERT + "XenoLinux Virtual Block Device Driver installed [device: %d]\n", + xlblk_major); + return 0; + + fail: + if (blk_ring->tx_ring) kfree(blk_ring->tx_ring); + if (blk_ring->rx_ring) kfree(blk_ring->rx_ring); + return error; +} + +void xlblk_ide_register_disk(int idx, unsigned long capacity) +{ + int units; + int minors; + struct gendisk *gd; + + /* plagarized from ide-probe.c::init_gendisk */ + + units = 2; /* from ide.h::MAX_DRIVES */ + + minors = units * (1<sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); + gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); + memset(gd->part, 0, minors * sizeof(struct hd_struct)); + + gd->major = xlblk_major; /* our major device number */ + gd->major_name = XLBLK_MAJOR_NAME; /* treated special in genhd.c */ + gd->minor_shift = IDE_PARTN_BITS; /* num bits for partitions */ + gd->max_p = 1<nr_real = units; /* current num real drives */ + gd->real_devices= NULL; /* ptr to internal data (was: hwif) */ + gd->next = NULL; /* linked list of major devs */ + gd->fops = &xenolinux_block_fops; /* file operations */ + gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL); + gd->flags = kmalloc (sizeof *gd->flags * units, GFP_KERNEL); + if (gd->de_arr) memset (gd->de_arr, 0, sizeof *gd->de_arr * units); + if (gd->flags) memset (gd->flags, 0, sizeof *gd->flags * units); + add_gendisk(gd); + + xen_disk_info.disks[idx].gendisk = gd; + + /* default disk size is just a big number. in the future, we + need a message to probe the devices to determine the actual size */ + register_disk(gd, MKDEV(xlblk_major, 0), 1< +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/******************************************************************/ + +static struct proc_dir_entry *bdt; +static blk_ring_entry_t meta; +static char * data; + +static int proc_read_bdt(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + switch (meta.operation) + { + case XEN_BLOCK_READ : + case XEN_BLOCK_WRITE : + { + return proc_dump_block(page, start, off, count, eof, data); + } + case XEN_BLOCK_DEBUG : + { + return proc_dump_debug(page, start, off, count, eof, data); + } + default : + { + printk(KERN_ALERT + "block device test error: unknown operation [%c]\n", + meta.operation); + return -EINVAL; + } + } +} + +int proc_dump_debug(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char header[100]; + char dump[1024]; + + sprintf (header, "Block Device Test: Debug Dump\n\n"); + + sprintf (dump, "%s\n", meta.buffer); + + if (data) + { + kfree(data); + } + + strncpy (page, dump, count); + return strlen(page); +} + +int proc_dump_block(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char header[100]; + char dump[1024]; + char temp[100]; + int loop; + + sprintf (header, "Block Device Test\n\n%s blk num: %ld 0x%lx; size: %d 0x%x; device: 0x%x\n", + meta.operation == XEN_BLOCK_WRITE ? "write" : "read", + meta.block_number, meta.block_number, + meta.block_size, meta.block_size, + meta.device); + + sprintf (dump, "%s", header); + + if (meta.buffer) + { + for (loop = 0; loop < 100; loop++) + { + int i = meta.buffer[loop]; + + if (loop % 8 == 0) + { + sprintf (temp, "[%2d] ", loop); + strcat(dump, temp); + } + else if (loop % 2 == 0) + { + strcat(dump, " "); + } + + sprintf (temp, " 0x%02x", i & 255); + strcat(dump, temp); + if ((loop + 1) % 8 == 0) + { + strcat(dump, "\n"); + } + } + strcat(dump, "\n\n"); + } + + if (data) + { + kfree(data); + } + + strncpy (page, dump, count); + return strlen(page); +} + +int proc_write_bdt(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL); + char opcode; + int block_number = 0; + int block_size = 0; + int device = 0; + int mode; + + if (copy_from_user(local, buffer, count)) + { + return -EFAULT; + } + local[count] = '\0'; + + sscanf(local, "%c %i %i %i", + &opcode, &block_number, &block_size, &device); + + if (opcode == 'r' || opcode == 'R') + { + meta.operation = XEN_BLOCK_READ; + } + else if (opcode == 'w' || opcode == 'W') + { + meta.operation = XEN_BLOCK_WRITE; + } + else if (opcode == 'd' || opcode == 'D') + { + meta.operation = XEN_BLOCK_DEBUG; + block_size = 10000; + } + else + { + printk(KERN_ALERT + "block device test error: unknown opcode [%c]\n", opcode); + return -EINVAL; + } + + if (opcode == 'r' || opcode == 'w' || + opcode == 'd' || opcode == 'D') + { + mode = XEN_BLOCK_SYNC; + } + else /* (opcode == 'R' || opcode == 'W') */ + { + mode = XEN_BLOCK_ASYNC; + } + + if (data) + { + kfree(data); + } + data = kmalloc(block_size * sizeof(char), GFP_KERNEL); + if (data == NULL) + { + kfree(local); + return -ENOMEM; + } + + meta.block_number = block_number; + meta.block_size = block_size; + meta.device = device; + meta.buffer = data; + + /* submit request */ + hypervisor_request(0, meta.operation, meta.buffer, + meta.block_number, meta.block_size, + meta.device, mode); + + kfree(local); + return count; +} + + +static int __init init_module(void) +{ + int return_value = 0; + + /* create proc entry */ + bdt = create_proc_entry("bdt", 0644, NULL); + if (bdt == NULL) + { + return_value = -ENOMEM; + goto error; + } + bdt->data = NULL; + bdt->read_proc = proc_read_bdt; + bdt->write_proc = proc_write_bdt; + bdt->owner = THIS_MODULE; + + memset(&meta, 0, sizeof(meta)); + + /* success */ + printk(KERN_ALERT "XenoLinux Block Device Test installed\n"); + return 0; + + error: + return return_value; +} + +static void __exit cleanup_module(void) +{ + if (data) + { + kfree(data); + } + printk(KERN_ALERT "XenoLinux Block Device Test uninstalled\n"); +} + +module_init(init_module); +module_exit(cleanup_module); diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c new file mode 100644 index 0000000000..97d4a65b78 --- /dev/null +++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c @@ -0,0 +1,27 @@ +/* + * domain 0 block driver interface + * + */ + +#include +#include +#include +#include + +static int __init init_module(void) +{ + request_module("xl_block"); + printk("Successfully installed domain 0 block interface\n"); + + + return 0; +} + +static void __exit cleanup_module(void) +{ + printk("Successfully de-installed domain-0 block interface\n"); + return 0; +} + +module_init(init_module); +module_exit(cleanup_module); diff --git a/xenolinux-2.4.16-sparse/drivers/block/Config.in b/xenolinux-2.4.16-sparse/drivers/block/Config.in new file mode 100644 index 0000000000..716774fe74 --- /dev/null +++ b/xenolinux-2.4.16-sparse/drivers/block/Config.in @@ -0,0 +1,51 @@ +# +# Block device driver configuration +# +mainmenu_option next_comment +comment 'Block devices' + +tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD +if [ "$CONFIG_AMIGA" = "y" ]; then + tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY +fi +if [ "$CONFIG_ATARI" = "y" ]; then + tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY +fi +if [ "$CONFIG_MAC" = "y" ]; then + dep_bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP $CONFIG_EXPERIMENTAL +fi +if [ "$CONFIG_MCA" = "y" ]; then + tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2 +fi +if [ "$CONFIG_ZORRO" = "y" ]; then + tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM +fi +if [ "$CONFIG_ATARI" = "y" ]; then + tristate 'Atari ACSI support' CONFIG_ATARI_ACSI + if [ "$CONFIG_ATARI_ACSI" != "n" ]; then + comment 'Some devices (e.g. CD jukebox) support multiple LUNs' + bool ' Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN + tristate ' Atari SLM laser printer support' CONFIG_ATARI_SLM + fi +fi +dep_tristate 'XT hard disk support' CONFIG_BLK_DEV_XD $CONFIG_ISA +dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT +if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then + source drivers/block/paride/Config.in +fi +dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI +dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI +dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI + +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET + +tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 +fi +dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM + +bool 'XenoLinux virtual block device support' CONFIG_XENOLINUX_BLOCK + +endmenu diff --git a/xenolinux-2.4.16-sparse/fs/partitions/check.c b/xenolinux-2.4.16-sparse/fs/partitions/check.c new file mode 100644 index 0000000000..e564544ec6 --- /dev/null +++ b/xenolinux-2.4.16-sparse/fs/partitions/check.c @@ -0,0 +1,443 @@ +/* + * Code extracted from drivers/block/genhd.c + * Copyright (C) 1991-1998 Linus Torvalds + * Re-organised Feb 1998 Russell King + * + * We now have independent partition support from the + * block drivers, which allows all the partition code to + * be grouped in one location, and it to be mostly self + * contained. + * + * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" + +#include "acorn.h" +#include "amiga.h" +#include "atari.h" +#include "ldm.h" +#include "mac.h" +#include "msdos.h" +#include "osf.h" +#include "sgi.h" +#include "sun.h" +#include "ibm.h" +#include "ultrix.h" + +extern int *blk_size[]; + +#define CHECK_DEBUG 0 + +int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ + +static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = { +#ifdef CONFIG_ACORN_PARTITION + acorn_partition, +#endif +#ifdef CONFIG_LDM_PARTITION + ldm_partition, /* this must come before msdos */ +#endif +#ifdef CONFIG_MSDOS_PARTITION + msdos_partition, +#endif +#ifdef CONFIG_OSF_PARTITION + osf_partition, +#endif +#ifdef CONFIG_SUN_PARTITION + sun_partition, +#endif +#ifdef CONFIG_AMIGA_PARTITION + amiga_partition, +#endif +#ifdef CONFIG_ATARI_PARTITION + atari_partition, +#endif +#ifdef CONFIG_MAC_PARTITION + mac_partition, +#endif +#ifdef CONFIG_SGI_PARTITION + sgi_partition, +#endif +#ifdef CONFIG_ULTRIX_PARTITION + ultrix_partition, +#endif +#ifdef CONFIG_IBM_PARTITION + ibm_partition, +#endif + NULL +}; + +/* + * This is ucking fugly but its probably the best thing for 2.4.x + * Take it as a clear reminder than we should put the device name + * generation in the object kdev_t points to in 2.5. + */ + +#ifdef CONFIG_ARCH_S390 +int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; +EXPORT_SYMBOL(genhd_dasd_name); +#endif + +/* + * disk_name() is used by partition check code and the md driver. + * It formats the devicename of the indicated disk into + * the supplied buffer (of size at least 32), and returns + * a pointer to that same buffer (for convenience). + */ + +char *disk_name (struct gendisk *hd, int minor, char *buf) +{ + const char *maj = hd->major_name; + unsigned int unit = (minor >> hd->minor_shift); + unsigned int part = (minor & ((1 << hd->minor_shift) -1 )); + + if ((unit < hd->nr_real) && hd->part[minor].de) { + int pos; + + pos = devfs_generate_path (hd->part[minor].de, buf, 64); + if (pos >= 0) + return buf + pos; + } + +#ifdef CONFIG_ARCH_S390 + if (genhd_dasd_name + && genhd_dasd_name (buf, unit, part, hd) == 0) + return buf; +#endif + /* + * IDE devices use multiple major numbers, but the drives + * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. + * This requires special handling here. + */ + switch (hd->major) { + case IDE9_MAJOR: + unit += 2; + case IDE8_MAJOR: + unit += 2; + case IDE7_MAJOR: + unit += 2; + case IDE6_MAJOR: + unit += 2; + case IDE5_MAJOR: + unit += 2; + case IDE4_MAJOR: + unit += 2; + case IDE3_MAJOR: + unit += 2; + case IDE2_MAJOR: + unit += 2; + case IDE1_MAJOR: + unit += 2; + case IDE0_MAJOR: + maj = "hd"; + break; + case MD_MAJOR: + sprintf(buf, "%s%d", maj, unit); + return buf; + } + if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { + unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; + if (unit+'a' > 'z') { + unit -= 26; + sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26); + if (part) + sprintf(buf + 4, "%d", part); + return buf; + } + } + if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) { + int ctlr = hd->major - COMPAQ_SMART2_MAJOR; + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); + return buf; + } + if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) { + int ctlr = hd->major - COMPAQ_CISS_MAJOR; + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); + return buf; + } + if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) { + int ctlr = hd->major - DAC960_MAJOR; + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); + return buf; + } + if (hd->major == ATARAID_MAJOR) { + int disk = minor >> hd->minor_shift; + int part = minor & (( 1 << hd->minor_shift) - 1); + if (part == 0) + sprintf(buf, "%s/d%d", maj, disk); + else + sprintf(buf, "%s/d%dp%d", maj, disk, part); + return buf; + } + if (part) + sprintf(buf, "%s%c%d", maj, unit+'a', part); + else + sprintf(buf, "%s%c", maj, unit+'a'); + return buf; +} + +/* + * Add a partitions details to the devices partition description. + */ +void add_gd_partition(struct gendisk *hd, int minor, int start, int size) +{ +#ifndef CONFIG_DEVFS_FS + char buf[40]; +#endif + + hd->part[minor].start_sect = start; + hd->part[minor].nr_sects = size; +#ifdef CONFIG_DEVFS_FS + printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); +#else + if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) || + (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7)) + printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); + else + printk(" %s", disk_name(hd, minor, buf)); +#endif +} + +static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor) +{ + devfs_handle_t de = NULL; + static int first_time = 1; + unsigned long first_sector; + struct block_device *bdev; + char buf[64]; + int i; + + if (CHECK_DEBUG) printk (KERN_ALERT "check.c::check_partition\n"); + + if (first_time) + printk(KERN_INFO "Partition check:\n"); + first_time = 0; + first_sector = hd->part[MINOR(dev)].start_sect; + + /* + * This is a kludge to allow the partition check to be + * skipped for specific drives (e.g. IDE CD-ROM drives) + */ + if ((int)first_sector == -1) { + hd->part[MINOR(dev)].start_sect = 0; + return; + } + + if (hd->de_arr) + de = hd->de_arr[MINOR(dev) >> hd->minor_shift]; + i = devfs_generate_path (de, buf, sizeof buf); + if (i >= 0) + printk(KERN_INFO " /dev/%s:", buf + i); + else + printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); + bdev = bdget(kdev_t_to_nr(dev)); + bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9; + bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev)); + for (i = 0; check_part[i]; i++) { + int res; + res = check_part[i](hd, bdev, first_sector, first_part_minor); + if (res) { + if (res < 0 && warn_no_part) + printk(" unable to read partition table\n"); + goto setup_devfs; + } + } + + printk(" unknown partition table\n"); +setup_devfs: + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + bdput(bdev); + i = first_part_minor - 1; + devfs_register_partitions (hd, i, hd->sizes ? 0 : 1); +} + +#ifdef CONFIG_DEVFS_FS +static void devfs_register_partition (struct gendisk *dev, int minor, int part) +{ + int devnum = minor >> dev->minor_shift; + devfs_handle_t dir; + unsigned int devfs_flags = DEVFS_FL_DEFAULT; + char devname[16]; + + if (dev->part[minor + part].de) return; + dir = devfs_get_parent (dev->part[minor].de); + if (!dir) return; + if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) ) + devfs_flags |= DEVFS_FL_REMOVABLE; + sprintf (devname, "part%d", part); + dev->part[minor + part].de = + devfs_register (dir, devname, devfs_flags, + dev->major, minor + part, + S_IFBLK | S_IRUSR | S_IWUSR, + dev->fops, NULL); +} + +static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER; + +static void devfs_register_disc (struct gendisk *dev, int minor) +{ + int pos = 0; + int devnum = minor >> dev->minor_shift; + devfs_handle_t dir, slave; + unsigned int devfs_flags = DEVFS_FL_DEFAULT; + char dirname[64], symlink[16]; + static devfs_handle_t devfs_handle; + + if (dev->part[minor].de) return; + if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) ) + devfs_flags |= DEVFS_FL_REMOVABLE; + if (dev->de_arr) { + dir = dev->de_arr[devnum]; + if (!dir) /* Aware driver wants to block disc management */ + return; + pos = devfs_generate_path (dir, dirname + 3, sizeof dirname-3); + if (pos < 0) return; + strncpy (dirname + pos, "../", 3); + } + else { + /* Unaware driver: construct "real" directory */ + sprintf (dirname, "../%s/disc%d", dev->major_name, devnum); + dir = devfs_mk_dir (NULL, dirname + 3, NULL); + } + if (!devfs_handle) + devfs_handle = devfs_mk_dir (NULL, "discs", NULL); + dev->part[minor].number = devfs_alloc_unique_number (&disc_numspace); + sprintf (symlink, "disc%d", dev->part[minor].number); + devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT, + dirname + pos, &slave, NULL); + dev->part[minor].de = + devfs_register (dir, "disc", devfs_flags, dev->major, minor, + S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL); + devfs_auto_unregister (dev->part[minor].de, slave); + if (!dev->de_arr) + devfs_auto_unregister (slave, dir); +} +#endif /* CONFIG_DEVFS_FS */ + +void devfs_register_partitions (struct gendisk *dev, int minor, int unregister) +{ +#ifdef CONFIG_DEVFS_FS + int part; + + if (!unregister) + devfs_register_disc (dev, minor); + for (part = 1; part < dev->max_p; part++) { + if ( unregister || (dev->part[part + minor].nr_sects < 1) ) { + devfs_unregister (dev->part[part + minor].de); + dev->part[part + minor].de = NULL; + continue; + } + devfs_register_partition (dev, minor, part); + } + if (unregister) { + devfs_unregister (dev->part[minor].de); + dev->part[minor].de = NULL; + devfs_dealloc_unique_number (&disc_numspace, + dev->part[minor].number); + } +#endif /* CONFIG_DEVFS_FS */ +} + +/* + * This function will re-read the partition tables for a given device, + * and set things back up again. There are some important caveats, + * however. You must ensure that no one is using the device, and no one + * can start using the device while this function is being executed. + * + * Much of the cleanup from the old partition tables should have already been + * done + */ + +void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors, + struct block_device_operations *ops, long size) +{ + if (CHECK_DEBUG) + { + if (gdev != NULL) + printk (KERN_ALERT + "check.c::register_disk gdev:%p dev:%d min:%u ops:%p sz:%ld\n", + gdev, dev, minors, ops, size); + } + + if (!gdev) + return; + + grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); +} + +void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) +{ + int i; + int first_minor = drive << dev->minor_shift; + int end_minor = first_minor + dev->max_p; + + if (CHECK_DEBUG) printk (KERN_ALERT "check.c::grok_partitions\n"); + + if(!dev->sizes) + blk_size[dev->major] = NULL; + + dev->part[first_minor].nr_sects = size; + /* No such device or no minors to use for partitions */ + if (!size || minors == 1) + return; + + if (dev->sizes) { + dev->sizes[first_minor] = size >> (BLOCK_SIZE_BITS - 9); + for (i = first_minor + 1; i < end_minor; i++) + dev->sizes[i] = 0; + } + blk_size[dev->major] = dev->sizes; + check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor); + + /* + * We need to set the sizes array before we will be able to access + * any of the partitions on this device. + */ + if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ + for (i = first_minor; i < end_minor; i++) + dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); + } +} + +unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p) +{ + struct address_space *mapping = bdev->bd_inode->i_mapping; + int sect = PAGE_CACHE_SIZE / 512; + struct page *page; + + page = read_cache_page(mapping, n/sect, + (filler_t *)mapping->a_ops->readpage, NULL); + if (!IS_ERR(page)) { + wait_on_page(page); + if (!Page_Uptodate(page)) + goto fail; + if (PageError(page)) + goto fail; + p->v = page; + return (unsigned char *)page_address(page) + 512 * (n % sect); +fail: + page_cache_release(page); + } + p->v = NULL; + return NULL; +} diff --git a/xenolinux-2.4.16-sparse/fs/partitions/msdos.c b/xenolinux-2.4.16-sparse/fs/partitions/msdos.c new file mode 100644 index 0000000000..34a086024e --- /dev/null +++ b/xenolinux-2.4.16-sparse/fs/partitions/msdos.c @@ -0,0 +1,642 @@ +/* + * fs/partitions/msdos.c + * + * Code extracted from drivers/block/genhd.c + * Copyright (C) 1991-1998 Linus Torvalds + * + * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug + * in the early extended-partition checks and added DM partitions + * + * Support for DiskManager v6.0x added by Mark Lord, + * with information provided by OnTrack. This now works for linux fdisk + * and LILO, as well as loadlin and bootln. Note that disks other than + * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). + * + * More flexible handling of extended partitions - aeb, 950831 + * + * Check partition table on IDE disks for common CHS translations + * + * Re-organised Feb 1998 Russell King + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_BLK_DEV_IDE +#include /* IDE xlate */ +#endif /* CONFIG_BLK_DEV_IDE */ + +#define MSDOS_DEBUG 0 + +#include + +#include "check.h" +#include "msdos.h" + +#if CONFIG_BLK_DEV_MD +extern void md_autodetect_dev(kdev_t dev); +#endif + +/* + * Many architectures don't like unaligned accesses, which is + * frequently the case with the nr_sects and start_sect partition + * table entries. + */ +#include + +#define SYS_IND(p) (get_unaligned(&p->sys_ind)) +#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \ + get_unaligned(&p->nr_sects); \ + le32_to_cpu(__a); \ + }) + +#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \ + get_unaligned(&p->start_sect); \ + le32_to_cpu(__a); \ + }) + +static inline int is_extended_partition(struct partition *p) +{ + return (SYS_IND(p) == DOS_EXTENDED_PARTITION || + SYS_IND(p) == WIN98_EXTENDED_PARTITION || + SYS_IND(p) == LINUX_EXTENDED_PARTITION); +} + +/* + * partition_name() formats the short partition name into the supplied + * buffer, and returns a pointer to that buffer. + * Used by several partition types which makes conditional inclusion messy, + * use __attribute__ ((unused)) instead. + */ +static char __attribute__ ((unused)) + *partition_name (struct gendisk *hd, int minor, char *buf) +{ +#ifdef CONFIG_DEVFS_FS + sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1))); + return buf; +#else + return disk_name(hd, minor, buf); +#endif +} + +#define MSDOS_LABEL_MAGIC1 0x55 +#define MSDOS_LABEL_MAGIC2 0xAA + +static inline int +msdos_magic_present(unsigned char *p) +{ + return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2); +} + +/* + * Create devices for each logical partition in an extended partition. + * The logical partitions form a linked list, with each entry being + * a partition table with two entries. The first entry + * is the real data partition (with a start relative to the partition + * table start). The second is a pointer to the next logical partition + * (with a start relative to the entire extended partition). + * We do not create a Linux partition for the partition tables, but + * only for the actual data partitions. + */ + +static void extended_partition(struct gendisk *hd, struct block_device *bdev, + int minor, unsigned long first_size, int *current_minor) +{ + struct partition *p; + Sector sect; + unsigned char *data; + unsigned long first_sector, this_sector, this_size; + int mask = (1 << hd->minor_shift) - 1; + int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512; + int loopct = 0; /* number of links followed + without finding a data partition */ + int i; + + this_sector = first_sector = hd->part[minor].start_sect; + this_size = first_size; + + while (1) { + if (++loopct > 100) + return; + if ((*current_minor & mask) == 0) + return; + data = read_dev_sector(bdev, this_sector, §); + if (!data) + return; + + if (!msdos_magic_present(data + 510)) + goto done; + + p = (struct partition *) (data + 0x1be); + + /* + * Usually, the first entry is the real data partition, + * the 2nd entry is the next extended partition, or empty, + * and the 3rd and 4th entries are unused. + * However, DRDOS sometimes has the extended partition as + * the first entry (when the data partition is empty), + * and OS/2 seems to use all four entries. + */ + + /* + * First process the data partition(s) + */ + for (i=0; i<4; i++, p++) { + unsigned long offs, size, next; + if (!NR_SECTS(p) || is_extended_partition(p)) + continue; + + /* Check the 3rd and 4th entries - + these sometimes contain random garbage */ + offs = START_SECT(p)*sector_size; + size = NR_SECTS(p)*sector_size; + next = this_sector + offs; + if (i >= 2) { + if (offs + size > this_size) + continue; + if (next < first_sector) + continue; + if (next + size > first_sector + first_size) + continue; + } + + add_gd_partition(hd, *current_minor, next, size); +#if CONFIG_BLK_DEV_MD + if (SYS_IND(p) == LINUX_RAID_PARTITION) { + md_autodetect_dev(MKDEV(hd->major,*current_minor)); + } +#endif + + (*current_minor)++; + loopct = 0; + if ((*current_minor & mask) == 0) + goto done; + } + /* + * Next, process the (first) extended partition, if present. + * (So far, there seems to be no reason to make + * extended_partition() recursive and allow a tree + * of extended partitions.) + * It should be a link to the next logical partition. + * Create a minor for this just long enough to get the next + * partition table. The minor will be reused for the next + * data partition. + */ + p -= 4; + for (i=0; i<4; i++, p++) + if (NR_SECTS(p) && is_extended_partition(p)) + break; + if (i == 4) + goto done; /* nothing left to do */ + + this_sector = first_sector + START_SECT(p) * sector_size; + this_size = NR_SECTS(p) * sector_size; + minor = *current_minor; + put_dev_sector(sect); + } +done: + put_dev_sector(sect); +} + +/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also + indicates linux swap. Be careful before believing this is Solaris. */ + +static void +solaris_x86_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ + +#ifdef CONFIG_SOLARIS_X86_PARTITION + long offset = hd->part[minor].start_sect; + Sector sect; + struct solaris_x86_vtoc *v; + struct solaris_x86_slice *s; + int mask = (1 << hd->minor_shift) - 1; + int i; + char buf[40]; + + v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §); + if (!v) + return; + if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { + put_dev_sector(sect); + return; + } + printk(" %s: v_version) != 1) { + printk(" cannot handle version %d vtoc>\n", + le32_to_cpu(v->v_version)); + put_dev_sector(sect); + return; + } + for (i=0; iv_slice[i]; + + if (s->s_size == 0) + continue; + printk(" [s%d]", i); + /* solaris partitions are relative to current MS-DOS + * one but add_gd_partition starts relative to sector + * zero of the disk. Therefore, must add the offset + * of the current partition */ + add_gd_partition(hd, *current_minor, + le32_to_cpu(s->s_start)+offset, + le32_to_cpu(s->s_size)); + (*current_minor)++; + } + put_dev_sector(sect); + printk(" >\n"); +#endif +} + +#ifdef CONFIG_BSD_DISKLABEL +static void +check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p, + int minor, int *current_minor) +{ + struct hd_struct *lin_p; + /* check relative position of partitions. */ + for (lin_p = hd->part + 1 + minor; + lin_p - hd->part - minor < *current_minor; lin_p++) { + /* no relationship -> try again */ + if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) || + lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) + continue; + /* equal -> no need to add */ + if (lin_p->start_sect == le32_to_cpu(bsd_p->p_offset) && + lin_p->nr_sects == le32_to_cpu(bsd_p->p_size)) + return; + /* bsd living within dos partition */ + if (lin_p->start_sect <= le32_to_cpu(bsd_p->p_offset) && lin_p->start_sect + + lin_p->nr_sects >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) { +#ifdef DEBUG_BSD_DISKLABEL + printk("w: %d %ld+%ld,%d+%d", + lin_p - hd->part, + lin_p->start_sect, lin_p->nr_sects, + le32_to_cpu(bsd_p->p_offset), + le32_to_cpu(bsd_p->p_size)); +#endif + break; + } + /* ouch: bsd and linux overlap. Don't even try for that partition */ +#ifdef DEBUG_BSD_DISKLABEL + printk("???: %d %ld+%ld,%d+%d", + lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects, + le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size)); +#endif + printk("???"); + return; + } /* if the bsd partition is not currently known to linux, we end + * up here + */ + add_gd_partition(hd, *current_minor, le32_to_cpu(bsd_p->p_offset), + le32_to_cpu(bsd_p->p_size)); + (*current_minor)++; +} + +/* + * Create devices for BSD partitions listed in a disklabel, under a + * dos-like partition. See extended_partition() for more information. + */ +static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor, char *name, int max_partitions) +{ + long offset = hd->part[minor].start_sect; + Sector sect; + struct bsd_disklabel *l; + struct bsd_partition *p; + int mask = (1 << hd->minor_shift) - 1; + char buf[40]; + + l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, §); + if (!l) + return; + if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) { + put_dev_sector(sect); + return; + } + printk(" %s: <%s", partition_name(hd, minor, buf), name); + + if (le16_to_cpu(l->d_npartitions) < max_partitions) + max_partitions = le16_to_cpu(l->d_npartitions); + for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { + if ((*current_minor & mask) == 0) + break; + if (p->p_fstype == BSD_FS_UNUSED) + continue; + check_and_add_bsd_partition(hd, p, minor, current_minor); + } + put_dev_sector(sect); + printk(" >\n"); +} +#endif + +static void bsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, "bsd", + BSD_MAXPARTITIONS); +#endif +} + +static void netbsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, "netbsd", + BSD_MAXPARTITIONS); +#endif +} + +static void openbsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, + "openbsd", OPENBSD_MAXPARTITIONS); +#endif +} + +/* + * Create devices for Unixware partitions listed in a disklabel, under a + * dos-like partition. See extended_partition() for more information. + */ +static void unixware_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_UNIXWARE_DISKLABEL + long offset = hd->part[minor].start_sect; + Sector sect; + struct unixware_disklabel *l; + struct unixware_slice *p; + int mask = (1 << hd->minor_shift) - 1; + char buf[40]; + + l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, §); + if (!l) + return; + if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC || + le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) { + put_dev_sector(sect); + return; + } + printk(" %s: vtoc.v_slice[1]; + /* I omit the 0th slice as it is the same as whole disk. */ + while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { + if ((*current_minor & mask) == 0) + break; + + if (p->s_label != UNIXWARE_FS_UNUSED) { + add_gd_partition(hd, *current_minor, START_SECT(p), + NR_SECTS(p)); + (*current_minor)++; + } + p++; + } + put_dev_sector(sect); + printk(" >\n"); +#endif +} + +/* + * Minix 2.0.0/2.0.2 subpartition support. + * Anand Krishnamurthy + * Rajeev V. Pillai + */ +static void minix_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_MINIX_SUBPARTITION + long offset = hd->part[minor].start_sect; + Sector sect; + unsigned char *data; + struct partition *p; + int mask = (1 << hd->minor_shift) - 1; + int i; + char buf[40]; + + data = read_dev_sector(bdev, offset, §); + if (!data) + return; + + p = (struct partition *)(data + 0x1be); + + /* The first sector of a Minix partition can have either + * a secondary MBR describing its subpartitions, or + * the normal boot sector. */ + if (msdos_magic_present (data + 510) && + SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ + + printk(" %s: \n"); + } + put_dev_sector(sect); +#endif /* CONFIG_MINIX_SUBPARTITION */ +} + +static struct { + unsigned char id; + void (*parse)(struct gendisk *, struct block_device *, int, int *); +} subtypes[] = { + {BSD_PARTITION, bsd_partition}, + {NETBSD_PARTITION, netbsd_partition}, + {OPENBSD_PARTITION, openbsd_partition}, + {MINIX_PARTITION, minix_partition}, + {UNIXWARE_PARTITION, unixware_partition}, + {SOLARIS_X86_PARTITION, solaris_x86_partition}, + {0, NULL}, +}; +/* + * Look for various forms of IDE disk geometry translation + */ +static int handle_ide_mess(struct block_device *bdev) +{ +#ifdef CONFIG_BLK_DEV_IDE + Sector sect; + unsigned char *data; + kdev_t dev = to_kdev_t(bdev->bd_dev); + unsigned int sig; + int heads = 0; + struct partition *p; + int i; + + if (MSDOS_DEBUG) + printk (KERN_ALERT "handle_ide_mess ------------\n"); + + /* + * The i386 partition handling programs very often + * make partitions end on cylinder boundaries. + * There is no need to do so, and Linux fdisk doesnt always + * do this, and Windows NT on Alpha doesnt do this either, + * but still, this helps to guess #heads. + */ + data = read_dev_sector(bdev, 0, §); + if (!data) + return -1; + if (!msdos_magic_present(data + 510)) { + put_dev_sector(sect); + return 0; + } + sig = le16_to_cpu(*(unsigned short *)(data + 2)); + p = (struct partition *) (data + 0x1be); + for (i = 0; i < 4; i++) { + struct partition *q = &p[i]; + if (NR_SECTS(q)) { + if ((q->sector & 63) == 1 && + (q->end_sector & 63) == 63) + heads = q->end_head + 1; + break; + } + } + if (SYS_IND(p) == EZD_PARTITION) { + /* + * Accesses to sector 0 must go to sector 1 instead. + */ + if (ide_xlate_1024(dev, -1, heads, " [EZD]")) + goto reread; + } else if (SYS_IND(p) == DM6_PARTITION) { + + /* + * Everything on the disk is offset by 63 sectors, + * including a "new" MBR with its own partition table. + */ + if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) + goto reread; + } else if (sig <= 0x1ae && + data[sig] == 0xAA && data[sig+1] == 0x55 && + (data[sig+2] & 1)) { + /* DM6 signature in MBR, courtesy of OnTrack */ + (void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]"); + } else if (SYS_IND(p) == DM6_AUX1PARTITION || + SYS_IND(p) == DM6_AUX3PARTITION) { + /* + * DM6 on other than the first (boot) drive + */ + (void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]"); + } else { + (void) ide_xlate_1024(dev, 2, heads, " [PTBL]"); + } + put_dev_sector(sect); + + if (MSDOS_DEBUG) + printk (KERN_ALERT "handle_ide_mess -------- %d\n", heads); + return 1; + +reread: + put_dev_sector(sect); + /* Flush the cache */ + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); +#endif /* CONFIG_BLK_DEV_IDE */ + return 1; +} + +int msdos_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor) +{ + int i, minor = first_part_minor; + Sector sect; + struct partition *p; + unsigned char *data; + int mask = (1 << hd->minor_shift) - 1; + int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512; + int current_minor = first_part_minor; + int err; + + if (MSDOS_DEBUG) printk (KERN_ALERT "msdos.c::msdos_partition\n"); + err = handle_ide_mess(bdev); + if (err <= 0) + return err; + data = read_dev_sector(bdev, 0, §); + if (!data) + return -1; + if (!msdos_magic_present(data + 510)) { + put_dev_sector(sect); + return 0; + } + p = (struct partition *) (data + 0x1be); + + /* + * Look for partitions in two passes: + * First find the primary and DOS-type extended partitions. + * On the second pass look inside *BSD, Unixware and Solaris partitions. + */ + + current_minor += 4; + for (i=1 ; i<=4 ; minor++,i++,p++) { + if (!NR_SECTS(p)) + continue; + add_gd_partition(hd, minor, + first_sector+START_SECT(p)*sector_size, + NR_SECTS(p)*sector_size); +#if CONFIG_BLK_DEV_MD + if (SYS_IND(p) == LINUX_RAID_PARTITION) { + md_autodetect_dev(MKDEV(hd->major,minor)); + } +#endif + if (is_extended_partition(p)) { + unsigned long size = hd->part[minor].nr_sects; + printk(" <"); + /* prevent someone doing mkfs or mkswap on an + extended partition, but leave room for LILO */ + if (size > 2) + hd->part[minor].nr_sects = 2; + extended_partition(hd, bdev, minor, size, ¤t_minor); + printk(" >"); + } + } + + /* + * Check for old-style Disk Manager partition table + */ + if (msdos_magic_present(data + 0xfc)) { + p = (struct partition *) (0x1be + data); + for (i = 4 ; i < 16 ; i++, current_minor++) { + p--; + if ((current_minor & mask) == 0) + break; + if (!(START_SECT(p) && NR_SECTS(p))) + continue; + add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); + } + } + printk("\n"); + + /* second pass - output for each on a separate line */ + minor -= 4; + p = (struct partition *) (0x1be + data); + for (i=1 ; i<=4 ; minor++,i++,p++) { + unsigned char id = SYS_IND(p); + int n; + + if (!NR_SECTS(p)) + continue; + + for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) + ; + + if (subtypes[n].parse) + subtypes[n].parse(hd, bdev, minor, ¤t_minor); + } + put_dev_sector(sect); + return 1; +} diff --git a/xenolinux-2.4.16-sparse/include/linux/blk.h b/xenolinux-2.4.16-sparse/include/linux/blk.h new file mode 100644 index 0000000000..12eb99ff16 --- /dev/null +++ b/xenolinux-2.4.16-sparse/include/linux/blk.h @@ -0,0 +1,416 @@ +#ifndef _BLK_H +#define _BLK_H + +#include +#include +#include +#include + +/* + * Spinlock for protecting the request queue which + * is mucked around with in interrupts on potentially + * multiple CPU's.. + */ +extern spinlock_t io_request_lock; + +/* + * Initialization functions. + */ +extern int isp16_init(void); +extern int cdu31a_init(void); +extern int acsi_init(void); +extern int mcd_init(void); +extern int mcdx_init(void); +extern int sbpcd_init(void); +extern int aztcd_init(void); +extern int sony535_init(void); +extern int gscd_init(void); +extern int cm206_init(void); +extern int optcd_init(void); +extern int sjcd_init(void); +extern int cdi_init(void); +extern int hd_init(void); +extern int ide_init(void); +extern int xd_init(void); +extern int mfm_init(void); +extern int loop_init(void); +extern int md_init(void); +extern int ap_init(void); +extern int ddv_init(void); +extern int z2_init(void); +extern int swim3_init(void); +extern int swimiop_init(void); +extern int amiga_floppy_init(void); +extern int atari_floppy_init(void); +extern int ez_init(void); +extern int bpcd_init(void); +extern int ps2esdi_init(void); +extern int jsfd_init(void); +extern int viodasd_init(void); +extern int viocd_init(void); +extern int xlblk_init(void); + +#if defined(CONFIG_ARCH_S390) +extern int dasd_init(void); +extern int xpram_init(void); +extern int tapeblock_init(void); +#endif /* CONFIG_ARCH_S390 */ + +extern void set_device_ro(kdev_t dev,int flag); +void add_blkdev_randomness(int major); + +extern int floppy_init(void); +extern void rd_load(void); +extern int rd_init(void); +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ + +#ifdef CONFIG_BLK_DEV_INITRD + +#define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */ + +extern unsigned long initrd_start,initrd_end; +extern int mount_initrd; /* zero if initrd should not be mounted */ +extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */ +void initrd_init(void); + +#endif + + +/* + * end_request() and friends. Must be called with the request queue spinlock + * acquired. All functions called within end_request() _must_be_ atomic. + * + * Several drivers define their own end_request and call + * end_that_request_first() and end_that_request_last() + * for parts of the original function. This prevents + * code duplication in drivers. + */ + +static inline void blkdev_dequeue_request(struct request * req) +{ + list_del(&req->queue); +} + +int end_that_request_first(struct request *req, int uptodate, char *name); +void end_that_request_last(struct request *req); + +#if defined(MAJOR_NR) || defined(IDE_DRIVER) + +#undef DEVICE_ON +#undef DEVICE_OFF + +/* + * Add entries as needed. + */ + +#ifdef IDE_DRIVER + +#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) +#define DEVICE_NAME "ide" + +#elif (MAJOR_NR == RAMDISK_MAJOR) + +/* ram disk */ +#define DEVICE_NAME "ramdisk" +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NO_RANDOM + +#elif (MAJOR_NR == Z2RAM_MAJOR) + +/* Zorro II Ram */ +#define DEVICE_NAME "Z2RAM" +#define DEVICE_REQUEST do_z2_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == FLOPPY_MAJOR) + +static void floppy_off(unsigned int nr); + +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 )) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == HD_MAJOR) + +/* Hard disk: timeout is 6 seconds. */ +#define DEVICE_NAME "hard disk" +#define DEVICE_INTR do_hd +#define TIMEOUT_VALUE (6*HZ) +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)>>6) + +#elif (SCSI_DISK_MAJOR(MAJOR_NR)) + +#define DEVICE_NAME "scsidisk" +#define TIMEOUT_VALUE (2*HZ) +#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4)) + +/* Kludge to use the same number for both char and block major numbers */ +#elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER) + +#define DEVICE_NAME "Multiple devices driver" +#define DEVICE_REQUEST do_md_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == SCSI_TAPE_MAJOR) + +#define DEVICE_NAME "scsitape" +#define DEVICE_INTR do_st +#define DEVICE_NR(device) (MINOR(device) & 0x7f) + +#elif (MAJOR_NR == OSST_MAJOR) + +#define DEVICE_NAME "onstream" +#define DEVICE_INTR do_osst +#define DEVICE_NR(device) (MINOR(device) & 0x7f) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == SCSI_CDROM_MAJOR) + +#define DEVICE_NAME "CD-ROM" +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == XT_DISK_MAJOR) + +#define DEVICE_NAME "xt disk" +#define DEVICE_REQUEST do_xd_request +#define DEVICE_NR(device) (MINOR(device) >> 6) + +#elif (MAJOR_NR == PS2ESDI_MAJOR) + +#define DEVICE_NAME "PS/2 ESDI" +#define DEVICE_REQUEST do_ps2esdi_request +#define DEVICE_NR(device) (MINOR(device) >> 6) + +#elif (MAJOR_NR == CDU31A_CDROM_MAJOR) + +#define DEVICE_NAME "CDU31A" +#define DEVICE_REQUEST do_cdu31a_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE)) + +#define DEVICE_NAME "ACSI" +#define DEVICE_INTR do_acsi +#define DEVICE_REQUEST do_acsi_request +#define DEVICE_NR(device) (MINOR(device) >> 4) + +#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR) + +#define DEVICE_NAME "Mitsumi CD-ROM" +/* #define DEVICE_INTR do_mcd */ +#define DEVICE_REQUEST do_mcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR) + +#define DEVICE_NAME "Mitsumi CD-ROM" +/* #define DEVICE_INTR do_mcdx */ +#define DEVICE_REQUEST do_mcdx_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #1" +#define DEVICE_REQUEST do_sbpcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #2" +#define DEVICE_REQUEST do_sbpcd2_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #3" +#define DEVICE_REQUEST do_sbpcd3_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #4" +#define DEVICE_REQUEST do_sbpcd4_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == AZTECH_CDROM_MAJOR) + +#define DEVICE_NAME "Aztech CD-ROM" +#define DEVICE_REQUEST do_aztcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == CDU535_CDROM_MAJOR) + +#define DEVICE_NAME "SONY-CDU535" +#define DEVICE_INTR do_cdu535 +#define DEVICE_REQUEST do_cdu535_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR) + +#define DEVICE_NAME "Goldstar R420" +#define DEVICE_REQUEST do_gscd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == CM206_CDROM_MAJOR) +#define DEVICE_NAME "Philips/LMS CD-ROM cm206" +#define DEVICE_REQUEST do_cm206_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == OPTICS_CDROM_MAJOR) + +#define DEVICE_NAME "DOLPHIN 8000AT CD-ROM" +#define DEVICE_REQUEST do_optcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == SANYO_CDROM_MAJOR) + +#define DEVICE_NAME "Sanyo H94A CD-ROM" +#define DEVICE_REQUEST do_sjcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == APBLOCK_MAJOR) + +#define DEVICE_NAME "apblock" +#define DEVICE_REQUEST ap_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == DDV_MAJOR) + +#define DEVICE_NAME "ddv" +#define DEVICE_REQUEST ddv_request +#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS) + +#elif (MAJOR_NR == MFM_ACORN_MAJOR) + +#define DEVICE_NAME "mfm disk" +#define DEVICE_INTR do_mfm +#define DEVICE_REQUEST do_mfm_request +#define DEVICE_NR(device) (MINOR(device) >> 6) + +#elif (MAJOR_NR == NBD_MAJOR) + +#define DEVICE_NAME "nbd" +#define DEVICE_REQUEST do_nbd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MDISK_MAJOR) + +#define DEVICE_NAME "mdisk" +#define DEVICE_REQUEST mdisk_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == DASD_MAJOR) + +#define DEVICE_NAME "dasd" +#define DEVICE_REQUEST do_dasd_request +#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) + +#elif (MAJOR_NR == I2O_MAJOR) + +#define DEVICE_NAME "I2O block" +#define DEVICE_REQUEST i2ob_request +#define DEVICE_NR(device) (MINOR(device)>>4) + +#elif (MAJOR_NR == COMPAQ_SMART2_MAJOR) + +#define DEVICE_NAME "ida" +#define TIMEOUT_VALUE (25*HZ) +#define DEVICE_REQUEST do_ida_request +#define DEVICE_NR(device) (MINOR(device) >> 4) + +#elif (MAJOR_NR == XLBLK_MAJOR) + +#define DEVICE_NAME "blk" +#define DEVICE_REQUEST do_xlblk_request +/* #define DEVICE_INTR */ +#define DEVICE_NR(device) (MINOR(device)) + +#endif /* MAJOR_NR == whatever */ + +/* provide DEVICE_xxx defaults, if not explicitly defined + * above in the MAJOR_NR==xxx if-elif tree */ +#ifndef DEVICE_ON +#define DEVICE_ON(device) do {} while (0) +#endif +#ifndef DEVICE_OFF +#define DEVICE_OFF(device) do {} while (0) +#endif + +#if (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR) +#if !defined(IDE_DRIVER) + +#ifndef CURRENT +#define CURRENT blkdev_entry_next_request(&blk_dev[MAJOR_NR].request_queue.queue_head) +#endif +#ifndef QUEUE_EMPTY +#define QUEUE_EMPTY list_empty(&blk_dev[MAJOR_NR].request_queue.queue_head) +#endif + +#ifndef DEVICE_NAME +#define DEVICE_NAME "unknown" +#endif + +#define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev) + +#ifdef DEVICE_INTR +static void (*DEVICE_INTR)(void) = NULL; +#endif + +#define SET_INTR(x) (DEVICE_INTR = (x)) + +#ifdef DEVICE_REQUEST +static void (DEVICE_REQUEST)(request_queue_t *); +#endif + +#ifdef DEVICE_INTR +#define CLEAR_INTR SET_INTR(NULL) +#else +#define CLEAR_INTR +#endif + +#define INIT_REQUEST \ + if (QUEUE_EMPTY) {\ + CLEAR_INTR; \ + return; \ + } \ + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!buffer_locked(CURRENT->bh)) \ + panic(DEVICE_NAME ": block not locked"); \ + } + +#endif /* !defined(IDE_DRIVER) */ + + +#ifndef LOCAL_END_REQUEST /* If we have our own end_request, we do not want to include this mess */ + +#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR) + +static inline void end_request(int uptodate) { + struct request *req = CURRENT; + + if (end_that_request_first(req, uptodate, DEVICE_NAME)) + return; + +#ifndef DEVICE_NO_RANDOM + add_blkdev_randomness(MAJOR(req->rq_dev)); +#endif + DEVICE_OFF(req->rq_dev); + blkdev_dequeue_request(req); + end_that_request_last(req); +} + +#endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */ +#endif /* LOCAL_END_REQUEST */ + +#endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) */ +#endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */ + +#endif /* _BLK_H */ diff --git a/xenolinux-2.4.16-sparse/include/linux/major.h b/xenolinux-2.4.16-sparse/include/linux/major.h new file mode 100644 index 0000000000..820bf68dc7 --- /dev/null +++ b/xenolinux-2.4.16-sparse/include/linux/major.h @@ -0,0 +1,199 @@ +#ifndef _LINUX_MAJOR_H +#define _LINUX_MAJOR_H + +/* + * This file has definitions for major device numbers. + * For the device number assignments, see Documentation/devices.txt. + */ + +/* limits */ + +/* + * Important: Don't change this to 256. Major number 255 is and must be + * reserved for future expansion into a larger dev_t space. + */ +#define MAX_CHRDEV 255 +#define MAX_BLKDEV 255 + +#define UNNAMED_MAJOR 0 +#define MEM_MAJOR 1 +#define RAMDISK_MAJOR 1 +#define FLOPPY_MAJOR 2 +#define PTY_MASTER_MAJOR 2 +#define IDE0_MAJOR 3 +#define PTY_SLAVE_MAJOR 3 +#define HD_MAJOR IDE0_MAJOR +#define TTY_MAJOR 4 +#define TTYAUX_MAJOR 5 +#define LP_MAJOR 6 +#define VCS_MAJOR 7 +#define LOOP_MAJOR 7 +#define SCSI_DISK0_MAJOR 8 +#define SCSI_TAPE_MAJOR 9 +#define MD_MAJOR 9 +#define MISC_MAJOR 10 +#define SCSI_CDROM_MAJOR 11 +#define QIC02_TAPE_MAJOR 12 +#define XT_DISK_MAJOR 13 +#define SOUND_MAJOR 14 +#define CDU31A_CDROM_MAJOR 15 +#define JOYSTICK_MAJOR 15 +#define GOLDSTAR_CDROM_MAJOR 16 +#define OPTICS_CDROM_MAJOR 17 +#define SANYO_CDROM_MAJOR 18 +#define CYCLADES_MAJOR 19 +#define CYCLADESAUX_MAJOR 20 +#define MITSUMI_X_CDROM_MAJOR 20 +#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ +#define SCSI_GENERIC_MAJOR 21 +#define Z8530_MAJOR 34 +#define DIGI_MAJOR 23 +#define IDE1_MAJOR 22 +#define DIGICU_MAJOR 22 +#define MITSUMI_CDROM_MAJOR 23 +#define CDU535_CDROM_MAJOR 24 +#define STL_SERIALMAJOR 24 +#define MATSUSHITA_CDROM_MAJOR 25 +#define STL_CALLOUTMAJOR 25 +#define MATSUSHITA_CDROM2_MAJOR 26 +#define QIC117_TAPE_MAJOR 27 +#define MATSUSHITA_CDROM3_MAJOR 27 +#define MATSUSHITA_CDROM4_MAJOR 28 +#define STL_SIOMEMMAJOR 28 +#define ACSI_MAJOR 28 +#define AZTECH_CDROM_MAJOR 29 +#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ +#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ +#define CM206_CDROM_MAJOR 32 +#define IDE2_MAJOR 33 +#define IDE3_MAJOR 34 +#define XPRAM_MAJOR 35 /* expanded storage on S/390 = "slow ram" */ + /* proposed by Peter */ +#define NETLINK_MAJOR 36 +#define PS2ESDI_MAJOR 36 +#define IDETAPE_MAJOR 37 +#define Z2RAM_MAJOR 37 +#define APBLOCK_MAJOR 38 /* AP1000 Block device */ +#define DDV_MAJOR 39 /* AP1000 DDV block device */ +#define NBD_MAJOR 43 /* Network block device */ +#define RISCOM8_NORMAL_MAJOR 48 +#define DAC960_MAJOR 48 /* 48..55 */ +#define RISCOM8_CALLOUT_MAJOR 49 +#define MKISS_MAJOR 55 +#define DSP56K_MAJOR 55 /* DSP56001 processor device */ + +#define IDE4_MAJOR 56 +#define IDE5_MAJOR 57 + +#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ + +#define SCSI_DISK1_MAJOR 65 +#define SCSI_DISK2_MAJOR 66 +#define SCSI_DISK3_MAJOR 67 +#define SCSI_DISK4_MAJOR 68 +#define SCSI_DISK5_MAJOR 69 +#define SCSI_DISK6_MAJOR 70 +#define SCSI_DISK7_MAJOR 71 + + +#define COMPAQ_SMART2_MAJOR 72 +#define COMPAQ_SMART2_MAJOR1 73 +#define COMPAQ_SMART2_MAJOR2 74 +#define COMPAQ_SMART2_MAJOR3 75 +#define COMPAQ_SMART2_MAJOR4 76 +#define COMPAQ_SMART2_MAJOR5 77 +#define COMPAQ_SMART2_MAJOR6 78 +#define COMPAQ_SMART2_MAJOR7 79 + +#define SPECIALIX_NORMAL_MAJOR 75 +#define SPECIALIX_CALLOUT_MAJOR 76 + +#define COMPAQ_CISS_MAJOR 104 +#define COMPAQ_CISS_MAJOR1 105 +#define COMPAQ_CISS_MAJOR2 106 +#define COMPAQ_CISS_MAJOR3 107 +#define COMPAQ_CISS_MAJOR4 108 +#define COMPAQ_CISS_MAJOR5 109 +#define COMPAQ_CISS_MAJOR6 110 +#define COMPAQ_CISS_MAJOR7 111 + +#define ATARAID_MAJOR 114 + +#define DASD_MAJOR 94 /* Official assignations from Peter */ + +#define MDISK_MAJOR 95 /* Official assignations from Peter */ + +#define I2O_MAJOR 80 /* 80->87 */ + +#define IDE6_MAJOR 88 +#define IDE7_MAJOR 89 +#define IDE8_MAJOR 90 +#define IDE9_MAJOR 91 + +#define UBD_MAJOR 98 + +#define AURORA_MAJOR 79 + +#define JSFD_MAJOR 99 + +#define PHONE_MAJOR 100 + +#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ + +#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ + +#define XLBLK_MAJOR 123 /* XenoLinux Block Device */ + +#define RTF_MAJOR 150 +#define RAW_MAJOR 162 + +#define USB_ACM_MAJOR 166 +#define USB_ACM_AUX_MAJOR 167 +#define USB_CHAR_MAJOR 180 + +#define UNIX98_PTY_MASTER_MAJOR 128 +#define UNIX98_PTY_MAJOR_COUNT 8 +#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) + +#define VXVM_MAJOR 199 /* VERITAS volume i/o driver */ +#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */ +#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */ + +#define MSR_MAJOR 202 +#define CPUID_MAJOR 203 + +#define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */ + +#define IBM_TTY3270_MAJOR 227 /* Official allocations now */ +#define IBM_FS3270_MAJOR 228 + +/* + * Tests for SCSI devices. + */ + +#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ + ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) + +#define SCSI_BLK_MAJOR(M) \ + (SCSI_DISK_MAJOR(M) \ + || (M) == SCSI_CDROM_MAJOR) + +static __inline__ int scsi_blk_major(int m) { + return SCSI_BLK_MAJOR(m); +} + +/* + * Tests for IDE devices + */ +#define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \ + (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \ + (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \ + (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \ + (M) == IDE8_MAJOR || (M) == IDE9_MAJOR) + +static __inline__ int ide_blk_major(int m) +{ + return IDE_DISK_MAJOR(m); +} + +#endif diff --git a/xenolinux-2.4.16-sparse/init/main.c b/xenolinux-2.4.16-sparse/init/main.c new file mode 100644 index 0000000000..a48a7773b8 --- /dev/null +++ b/xenolinux-2.4.16-sparse/init/main.c @@ -0,0 +1,871 @@ +/* + * linux/init/main.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * GK 2/5/95 - Changed to support mounting root fs via NFS + * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 + * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 + * Simplified starting of init: Michael A. Griffith + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_ARCH_S390) +#include +#include +#endif + +#ifdef CONFIG_PCI +#include +#endif + +#ifdef CONFIG_DIO +#include +#endif + +#ifdef CONFIG_ZORRO +#include +#endif + +#ifdef CONFIG_MTRR +# include +#endif + +#ifdef CONFIG_NUBUS +#include +#endif + +#ifdef CONFIG_ISAPNP +#include +#endif + +#ifdef CONFIG_IRDA +extern int irda_proto_init(void); +extern int irda_device_init(void); +#endif + +#ifdef CONFIG_X86_LOCAL_APIC +#include +#endif + +#if defined(CONFIG_KDB) +#include +#endif + +/* + * Versions of gcc older than that listed below may actually compile + * and link okay, but the end product can have subtle run time bugs. + * To avoid associated bogus bug reports, we flatly refuse to compile + * with a gcc that is known to be too old from the very beginning. + */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) +#error Sorry, your GCC is too old. It builds incorrect kernels. +#endif + +extern char _stext, _etext; +extern char *linux_banner; + +static int init(void *); + +extern void init_IRQ(void); +extern void init_modules(void); +extern void sock_init(void); +extern void fork_init(unsigned long); +extern void mca_init(void); +extern void sbus_init(void); +extern void ppc_init(void); +extern void sysctl_init(void); +extern void signals_init(void); +extern int init_pcmcia_ds(void); + +extern void free_initmem(void); + +#ifdef CONFIG_TC +extern void tc_init(void); +#endif + +extern void ecard_init(void); + +#if defined(CONFIG_SYSVIPC) +extern void ipc_init(void); +#endif + +/* + * Boot command-line arguments + */ +#define MAX_INIT_ARGS 8 +#define MAX_INIT_ENVS 8 + +extern void time_init(void); +extern void softirq_init(void); + +int rows, cols; + +#ifdef CONFIG_BLK_DEV_INITRD +unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ +#endif + +int root_mountflags = MS_RDONLY; +char *execute_command; +char root_device_name[64]; + + +static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; +static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; + +static int __init profile_setup(char *str) +{ + int par; + if (get_option(&str,&par)) prof_shift = par; + return 1; +} + +__setup("profile=", profile_setup); + + +static struct dev_name_struct { + const char *name; + const int num; +} root_dev_names[] __initdata = { + { "nfs", 0x00ff }, + { "blk", 0x7b00 }, + { "hda", 0x0300 }, + { "hdb", 0x0340 }, + { "loop", 0x0700 }, + { "hdc", 0x1600 }, + { "hdd", 0x1640 }, + { "hde", 0x2100 }, + { "hdf", 0x2140 }, + { "hdg", 0x2200 }, + { "hdh", 0x2240 }, + { "hdi", 0x3800 }, + { "hdj", 0x3840 }, + { "hdk", 0x3900 }, + { "hdl", 0x3940 }, + { "hdm", 0x5800 }, + { "hdn", 0x5840 }, + { "hdo", 0x5900 }, + { "hdp", 0x5940 }, + { "hdq", 0x5A00 }, + { "hdr", 0x5A40 }, + { "hds", 0x5B00 }, + { "hdt", 0x5B40 }, + { "sda", 0x0800 }, + { "sdb", 0x0810 }, + { "sdc", 0x0820 }, + { "sdd", 0x0830 }, + { "sde", 0x0840 }, + { "sdf", 0x0850 }, + { "sdg", 0x0860 }, + { "sdh", 0x0870 }, + { "sdi", 0x0880 }, + { "sdj", 0x0890 }, + { "sdk", 0x08a0 }, + { "sdl", 0x08b0 }, + { "sdm", 0x08c0 }, + { "sdn", 0x08d0 }, + { "sdo", 0x08e0 }, + { "sdp", 0x08f0 }, + { "ada", 0x1c00 }, + { "adb", 0x1c10 }, + { "adc", 0x1c20 }, + { "add", 0x1c30 }, + { "ade", 0x1c40 }, + { "fd", 0x0200 }, + { "md", 0x0900 }, + { "xda", 0x0d00 }, + { "xdb", 0x0d40 }, + { "ram", 0x0100 }, + { "scd", 0x0b00 }, + { "mcd", 0x1700 }, + { "cdu535", 0x1800 }, + { "sonycd", 0x1800 }, + { "aztcd", 0x1d00 }, + { "cm206cd", 0x2000 }, + { "gscd", 0x1000 }, + { "sbpcd", 0x1900 }, + { "eda", 0x2400 }, + { "edb", 0x2440 }, + { "pda", 0x2d00 }, + { "pdb", 0x2d10 }, + { "pdc", 0x2d20 }, + { "pdd", 0x2d30 }, + { "pcd", 0x2e00 }, + { "pf", 0x2f00 }, + { "apblock", APBLOCK_MAJOR << 8}, + { "ddv", DDV_MAJOR << 8}, + { "jsfd", JSFD_MAJOR << 8}, +#if defined(CONFIG_ARCH_S390) + { "dasda", (DASD_MAJOR << MINORBITS) }, + { "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) }, + { "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) }, + { "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) }, + { "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) }, + { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) }, + { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) }, + { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) }, +#endif +#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE) + { "ida/c0d0p",0x4800 }, + { "ida/c0d1p",0x4810 }, + { "ida/c0d2p",0x4820 }, + { "ida/c0d3p",0x4830 }, + { "ida/c0d4p",0x4840 }, + { "ida/c0d5p",0x4850 }, + { "ida/c0d6p",0x4860 }, + { "ida/c0d7p",0x4870 }, + { "ida/c0d8p",0x4880 }, + { "ida/c0d9p",0x4890 }, + { "ida/c0d10p",0x48A0 }, + { "ida/c0d11p",0x48B0 }, + { "ida/c0d12p",0x48C0 }, + { "ida/c0d13p",0x48D0 }, + { "ida/c0d14p",0x48E0 }, + { "ida/c0d15p",0x48F0 }, +#endif +#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE) + { "cciss/c0d0p",0x6800 }, + { "cciss/c0d1p",0x6810 }, + { "cciss/c0d2p",0x6820 }, + { "cciss/c0d3p",0x6830 }, + { "cciss/c0d4p",0x6840 }, + { "cciss/c0d5p",0x6850 }, + { "cciss/c0d6p",0x6860 }, + { "cciss/c0d7p",0x6870 }, + { "cciss/c0d8p",0x6880 }, + { "cciss/c0d9p",0x6890 }, + { "cciss/c0d10p",0x68A0 }, + { "cciss/c0d11p",0x68B0 }, + { "cciss/c0d12p",0x68C0 }, + { "cciss/c0d13p",0x68D0 }, + { "cciss/c0d14p",0x68E0 }, + { "cciss/c0d15p",0x68F0 }, +#endif + { "nftla", 0x5d00 }, + { "nftlb", 0x5d10 }, + { "nftlc", 0x5d20 }, + { "nftld", 0x5d30 }, + { "ftla", 0x2c00 }, + { "ftlb", 0x2c08 }, + { "ftlc", 0x2c10 }, + { "ftld", 0x2c18 }, + { "mtdblock", 0x1f00 }, + { NULL, 0 } +}; + +kdev_t __init name_to_kdev_t(char *line) +{ + int base = 0; + + if (strncmp(line,"/dev/",5) == 0) { + struct dev_name_struct *dev = root_dev_names; + line += 5; + do { + int len = strlen(dev->name); + if (strncmp(line,dev->name,len) == 0) { + line += len; + base = dev->num; + break; + } + dev++; + } while (dev->name); + } + return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16)); +} + +static int __init root_dev_setup(char *line) +{ + int i; + char ch; + + ROOT_DEV = name_to_kdev_t(line); + memset (root_device_name, 0, sizeof root_device_name); + if (strncmp (line, "/dev/", 5) == 0) line += 5; + for (i = 0; i < sizeof root_device_name - 1; ++i) + { + ch = line[i]; + if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break; + root_device_name[i] = ch; + } + return 1; +} + +__setup("root=", root_dev_setup); + +static int __init checksetup(char *line) +{ + struct kernel_param *p; + + p = &__setup_start; + do { + int n = strlen(p->str); + if (!strncmp(line,p->str,n)) { + if (p->setup_func(line+n)) + return 1; + } + p++; + } while (p < &__setup_end); + return 0; +} + +/* this should be approx 2 Bo*oMips to start (note initial shift), and will + still work even if initially too large, it will just take slightly longer */ +unsigned long loops_per_jiffy = (1<<12); + +/* This is the number of bits of precision for the loops_per_jiffy. Each + bit takes on average 1.5/HZ seconds. This (like the original) is a little + better than 1% */ +#define LPS_PREC 8 + +void __init calibrate_delay(void) +{ + unsigned long ticks, loopbit; + int lps_precision = LPS_PREC; + + loops_per_jiffy = (1<<12); + + printk("Calibrating delay loop... "); + while (loops_per_jiffy <<= 1) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_jiffy); + ticks = jiffies - ticks; + if (ticks) + break; + } + +/* Do a binary approximation to get loops_per_jiffy set to equal one clock + (up to lps_precision bits) */ + loops_per_jiffy >>= 1; + loopbit = loops_per_jiffy; + while ( lps_precision-- && (loopbit >>= 1) ) { + loops_per_jiffy |= loopbit; + ticks = jiffies; + while (ticks == jiffies); + ticks = jiffies; + __delay(loops_per_jiffy); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_jiffy &= ~loopbit; + } + +/* Round the value and print it */ + printk("%lu.%02lu BogoMIPS\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); +} + +static int __init readonly(char *str) +{ + if (*str) + return 0; + root_mountflags |= MS_RDONLY; + return 1; +} + +static int __init readwrite(char *str) +{ + if (*str) + return 0; + root_mountflags &= ~MS_RDONLY; + return 1; +} + +static int __init debug_kernel(char *str) +{ + if (*str) + return 0; + console_loglevel = 10; + return 1; +} + +static int __init quiet_kernel(char *str) +{ + if (*str) + return 0; + console_loglevel = 4; + return 1; +} + +__setup("ro", readonly); +__setup("rw", readwrite); +__setup("debug", debug_kernel); +__setup("quiet", quiet_kernel); + +/* + * This is a simple kernel command line parsing function: it parses + * the command line, and fills in the arguments/environment to init + * as appropriate. Any cmd-line option is taken to be an environment + * variable if it contains the character '='. + * + * This routine also checks for options meant for the kernel. + * These options are not given to init - they are for internal kernel use only. + */ +static void __init parse_options(char *line) +{ + char *next,*quote; + int args, envs; + + if (!*line) + return; + args = 0; + envs = 1; /* TERM is set to 'linux' by default */ + next = line; + while ((line = next) != NULL) { + quote = strchr(line,'"'); + next = strchr(line, ' '); + while (next != NULL && quote != NULL && quote < next) { + /* we found a left quote before the next blank + * now we have to find the matching right quote + */ + next = strchr(quote+1, '"'); + if (next != NULL) { + quote = strchr(next+1, '"'); + next = strchr(next+1, ' '); + } + } + if (next != NULL) + *next++ = 0; +#if defined(CONFIG_KDB) + /* kdb, kdb=on, kdb=off, kdb=early */ + if (strncmp(line, "kdb", 3) == 0) { + if (line[3] == '\0') { + /* Backward compatibility, kdb with no option means early activation */ + printk("Boot flag kdb with no options is obsolete, use kdb=early\n"); + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + if (line[3] == '=') { + if (strcmp(line+4, "on") == 0) { + kdb_on = 1; + continue; + } + if (strcmp(line+4, "off") == 0) { + kdb_on = 0; + continue; + } + if (strcmp(line+4, "early") == 0) { + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + printk("Boot flag %s not recognised, assumed to be environment variable\n", line); + } + } +#endif + if (!strncmp(line,"init=",5)) { + line += 5; + execute_command = line; + /* In case LILO is going to boot us with default command line, + * it prepends "auto" before the whole cmdline which makes + * the shell think it should execute a script with such name. + * So we ignore all arguments entered _before_ init=... [MJ] + */ + args = 0; + continue; + } + if (checksetup(line)) + continue; + + /* + * Then check if it's an environment variable or + * an option. + */ + if (strchr(line,'=')) { + if (envs >= MAX_INIT_ENVS) + break; + envp_init[++envs] = line; + } else { + if (args >= MAX_INIT_ARGS) + break; + if (*line) + argv_init[++args] = line; + } + } + argv_init[args+1] = NULL; + envp_init[envs+1] = NULL; +} + + +extern void setup_arch(char **); +extern void cpu_idle(void); + +unsigned long wait_init_idle; + +#ifndef CONFIG_SMP + +#ifdef CONFIG_X86_LOCAL_APIC +static void __init smp_init(void) +{ + APIC_init_uniprocessor(); +} +#else +#define smp_init() do { } while (0) +#endif + +#else + + +/* Called by boot processor to activate the rest. */ +static void __init smp_init(void) +{ + /* Get other processors into their bootup holding patterns. */ + smp_boot_cpus(); + wait_init_idle = cpu_online_map; + clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */ + + smp_threads_ready=1; + smp_commence(); + + /* Wait for the other cpus to set up their idle processes */ + printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle); + while (wait_init_idle) { + cpu_relax(); + barrier(); + } + printk("All processors have done init_idle\n"); +} + +#endif + +/* + * We need to finalize in a non-__init function or else race conditions + * between the root thread and the init thread may cause start_kernel to + * be reaped by free_initmem before the root thread has proceeded to + * cpu_idle. + */ + +static void rest_init(void) +{ + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + unlock_kernel(); + current->need_resched = 1; + cpu_idle(); +} + +/* + * Activate the first processor. + */ + +asmlinkage void __init start_kernel(void) +{ + char * command_line; + unsigned long mempages; + extern char saved_command_line[]; +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + lock_kernel(); + printk(linux_banner); + setup_arch(&command_line); + printk("Kernel command line: %s\n", saved_command_line); + parse_options(command_line); + trap_init(); + init_IRQ(); + sched_init(); + softirq_init(); + time_init(); + + /* + * HACK ALERT! This is early. We're enabling the console before + * we've done PCI setups etc, and console_init() must be aware of + * this. But we do want output early, in case something goes wrong. + */ + console_init(); +#ifdef CONFIG_MODULES + init_modules(); +#endif + if (prof_shift) { + unsigned int size; + /* only text is profiled */ + prof_len = (unsigned long) &_etext - (unsigned long) &_stext; + prof_len >>= prof_shift; + + size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1; + prof_buffer = (unsigned int *) alloc_bootmem(size); + } + + kmem_cache_init(); + sti(); + calibrate_delay(); +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start && !initrd_below_start_ok && + initrd_start < min_low_pfn << PAGE_SHIFT) { + printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " + "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT); + initrd_start = 0; + } +#endif + mem_init(); + kmem_cache_sizes_init(); +#if defined(CONFIG_KDB) + kdb_init(); + if (KDB_FLAG(EARLYKDB)) { + KDB_ENTER(); + } +#endif + mempages = num_physpages; + + fork_init(mempages); + proc_caches_init(); + vfs_caches_init(mempages); + buffer_init(mempages); + page_cache_init(mempages); +#if defined(CONFIG_ARCH_S390) + ccwcache_init(); +#endif + signals_init(); +#ifdef CONFIG_PROC_FS + proc_root_init(); +#endif +#if defined(CONFIG_SYSVIPC) + ipc_init(); +#endif + check_bugs(); + printk("POSIX conformance testing by UNIFIX\n"); + + /* + * We count on the initial thread going ok + * Like idlers init is an unlocked kernel thread, which will + * make syscalls (and thus be locked). + */ + smp_init(); + rest_init(); +} + +#ifdef CONFIG_BLK_DEV_INITRD +static int do_linuxrc(void * shell) +{ + static char *argv[] = { "linuxrc", NULL, }; + + close(0);close(1);close(2); + setsid(); + (void) open("/dev/console",O_RDWR,0); + (void) dup(0); + (void) dup(0); + return execve(shell, argv, envp_init); +} + +#endif + +struct task_struct *child_reaper = &init_task; + +static void __init do_initcalls(void) +{ + initcall_t *call; + + call = &__initcall_start; + do { + (*call)(); + call++; + } while (call < &__initcall_end); + + /* Make sure there is no pending stuff from the initcall sequence */ + flush_scheduled_tasks(); +} + +/* + * Ok, the machine is now initialized. None of the devices + * have been touched yet, but the CPU subsystem is up and + * running, and memory and process management works. + * + * Now we can finally start doing some real work.. + */ +static void __init do_basic_setup(void) +{ + + /* + * Tell the world that we're going to be the grim + * reaper of innocent orphaned children. + * + * We don't want people to have to make incorrect + * assumptions about where in the task array this + * can be found. + */ + child_reaper = current; + +#if defined(CONFIG_MTRR) /* Do this after SMP initialization */ +/* + * We should probably create some architecture-dependent "fixup after + * everything is up" style function where this would belong better + * than in init/main.c.. + */ + mtrr_init(); +#endif + +#ifdef CONFIG_SYSCTL + sysctl_init(); +#endif + + /* + * Ok, at this point all CPU's should be initialized, so + * we can start looking into devices.. + */ +#if defined(CONFIG_ARCH_S390) + s390_init_machine_check(); +#endif + +#ifdef CONFIG_PCI + pci_init(); +#endif +#ifdef CONFIG_SBUS + sbus_init(); +#endif +#if defined(CONFIG_PPC) + ppc_init(); +#endif +#ifdef CONFIG_MCA + mca_init(); +#endif +#ifdef CONFIG_ARCH_ACORN + ecard_init(); +#endif +#ifdef CONFIG_ZORRO + zorro_init(); +#endif +#ifdef CONFIG_DIO + dio_init(); +#endif +#ifdef CONFIG_NUBUS + nubus_init(); +#endif +#ifdef CONFIG_ISAPNP + isapnp_init(); +#endif +#ifdef CONFIG_TC + tc_init(); +#endif + + /* Networking initialization needs a process context */ + sock_init(); + + start_context_thread(); + do_initcalls(); + +#ifdef CONFIG_IRDA + irda_proto_init(); + irda_device_init(); /* Must be done after protocol initialization */ +#endif +#ifdef CONFIG_PCMCIA + init_pcmcia_ds(); /* Do this last */ +#endif +} + +extern void rd_load(void); +extern void initrd_load(void); + +/* + * Prepare the namespace - decide what/where to mount, load ramdisks, etc. + */ +static void prepare_namespace(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + int real_root_mountflags = root_mountflags; + if (!initrd_start) + mount_initrd = 0; + if (mount_initrd) + root_mountflags &= ~MS_RDONLY; + real_root_dev = ROOT_DEV; +#endif + +#ifdef CONFIG_BLK_DEV_RAM +#ifdef CONFIG_BLK_DEV_INITRD + if (mount_initrd) + initrd_load(); + else +#endif + rd_load(); +#endif + + /* Mount the root filesystem.. */ + mount_root(); + + mount_devfs_fs (); + +#ifdef CONFIG_BLK_DEV_INITRD + root_mountflags = real_root_mountflags; + if (mount_initrd && ROOT_DEV != real_root_dev + && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { + int error; + int i, pid; + + pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); + if (pid > 0) { + while (pid != wait(&i)) { + current->policy |= SCHED_YIELD; + schedule(); + } + } + if (MAJOR(real_root_dev) != RAMDISK_MAJOR + || MINOR(real_root_dev) != 0) { + error = change_root(real_root_dev,"/initrd"); + if (error) + printk(KERN_ERR "Change root to /initrd: " + "error %d\n",error); + } + } +#endif +} + +static int init(void * unused) +{ + lock_kernel(); + do_basic_setup(); + + prepare_namespace(); + + /* + * Ok, we have completed the initial bootup, and + * we're essentially up and running. Get rid of the + * initmem segments and start the user-mode stuff.. + */ + free_initmem(); + unlock_kernel(); + + if (open("/dev/console", O_RDWR, 0) < 0) + printk("Warning: unable to open an initial console.\n"); + + (void) dup(0); + (void) dup(0); + + /* + * We try each of these until one succeeds. + * + * The Bourne shell can be used instead of init if we are + * trying to recover a really broken machine. + */ + + if (execute_command) + execve(execute_command,argv_init,envp_init); + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); + execve("/bin/sh",argv_init,envp_init); + panic("No init found. Try passing init= option to kernel."); +} -- 2.30.2